I am trying to filter an array of places into multiple arrays depending on the city, state (which I have labeled as address) of the place. I want all of the place objects with the same address to be grouped into one array so I can use that address as a header for each section in my tableView. I just don't know how to do it. I am not sure how to show any code for this but I have tried
filteredPlaces.append(places.filter({ $0.address }))
That didn't work at all.
I tried to loop through the places
array, but I wasn't sure what code I needed in order to identify if any of the objects had the same address.
My current filteredPlaces
array looks like this:
var filteredPlaces = [[Place]()]
and my current array that is holding all of the places, looks like this: var places = [Place]()
Before this gets down voted, please tell me what I can do to explain better because I am not sure how else to ask this question more clearly. How can I create separate arrays based on the address of each place in one array? Thanks for your help!
EDIT TO ADD: Here is my place object class
class Place {
var name: String
var street: String
var city: String
var state: String
var zip: String
var drinks: [Drink]
var address: String {
return "\(city), \(state)"
}
init(name: String, street: String, city: String, state: String, zip: String, drinks: [Drink]) {
self.name = name.uppercased()
self.street = street.uppercased()
self.city = city.uppercased()
self.state = state.uppercased()
self.drinks = drinks
self.zip = zip
}
convenience init(name: String, street: String, city: String, state: String, zip: String, drinks: [Drink]?) {
if drinks != nil {
self.init(name: name, street: street, city: city, state: state, zip: zip, drinks: drinks)
} else {
self.init(name: name, street: street, city: city, state: state, zip: zip, drinks: [Drink]())
}
}
}
I haven't created the declaration yet because that will be done when a user enters the places on a new viewController.
CodePudding user response:
You can use Dictionary(grouping:by:)
The example is like
/// let students = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"]
/// let studentsByLetter = Dictionary(grouping: students, by: { $0.first! })
/// // ["E": ["Efua"], "K": ["Kofi", "Kweku"], "A": ["Abena", "Akosua"]]
In your case you need something hashable for the key of the dictionary, so a hashable pair of place and street names:
struct PlaceNameStreet: Hashable {
let name: String
let street: String
}
let dictionary = Dictionary(grouping: places) { place in
PlaceNameStreet(name: place.name, street: place.street)
}
CodePudding user response:
you could try something like this, to obtain an dictionary of adresses
with Places
.
EDIT-1: using your Place
class.
// example Places, 2 in Tokyo, and 3 in Sydney
var places = [
Place(name: "place-1", street: "street-1", city: "Tokyo", state: "Kanto", zip: "123", drinks: []),
Place(name: "place-2", street: "street-2", city: "Tokyo", state: "Kanto", zip: "123", drinks: []),
Place(name: "place-1", street: "street-1", city: "Sydney", state: "NSW", zip: "123", drinks: []),
Place(name: "place-2", street: "street-2", city: "Sydney", state: "NSW", zip: "123", drinks: []),
Place(name: "place-3", street: "street-3", city: "Sydney", state: "NSW", zip: "123", drinks: [])]
// just for info
let adrss = Set(places.map{$0.address})
print("\n---> unique adresses: \(adrss) \n")
// returns a dictionary where the key is the address and the value are the Places
let allPlaces: [String:[Place]] = Set(places.map{$0.address}).reduce(into: [:]) { dict, adrs in
dict[adrs] = places.filter{$0.address == adrs}
}
// an array of all places in Sydney
print("\n---> all Places in Sydney: \(allPlaces["Sydney"]) \n")
// an array of all places in Tokyo
print("\n---> all Places in Tokyo: \(allPlaces["Tokyo"]) \n")
The term Set(places.map{$0.address})
gives you all unique addresses.
the .reduce(into: [:])
, accumulates the Places
for each address.
The result is a dictionary, with the key=the address and the value=the array of Place
Example usage:
struct ContentView: View {
@State var allPlaces: [String:[Place]] = [:]
var body: some View {
ForEach(allPlaces.keys.sorted(), id: \.self) { key in
HStack {
if let plcs = allPlaces[key] {
Text("\(plcs.count) places in")
} else {
Text("no places in")
}
Text(key).foregroundColor(.blue)
}
}
.onAppear {
// example Places, 2 in Tokyo, and 3 in Sydney
var places = [
Place(name: "place-1", street: "street-1", city: "Tokyo", state: "Kanto", zip: "123", drinks: []),
Place(name: "place-2", street: "street-2", city: "Tokyo", state: "Kanto", zip: "123", drinks: []),
Place(name: "place-1", street: "street-1", city: "Sydney", state: "NSW", zip: "123", drinks: []),
Place(name: "place-2", street: "street-2", city: "Sydney", state: "NSW", zip: "123", drinks: []),
Place(name: "place-3", street: "street-3", city: "Sydney", state: "NSW", zip: "123", drinks: [])]
// returns a dictionary where the key is the address and the value are the Places
allPlaces = Set(places.map{$0.address}).reduce(into: [:]) { dict, adrs in
dict[adrs] = places.filter{$0.address == adrs}
}
}
}
}