skip to Main Content

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]()

How can I create separate arrays based on the address of each place in one array?

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.

2

Answers


  1. 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, NSW"]) n")
     // an array of all places in Tokyo
     print("n---> all Places in Tokyo: (allPlaces["TOKYO, KANTO"]) 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 {
        List {
            ForEach(allPlaces.keys.sorted(), id: .self) { key in
                Section(header: Text(key)) {
                    ForEach(allPlaces[key] ?? []) { place in
                        Text(place.name)
                    }
                }
            }
        }
            .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}
                }
            }
        }
    }
    
    Login or Signup to reply.
  2. 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)
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search