1

In my app I have two struct arrays and I want to remove common items from one of them. My struct:

struct PeopleSelectItem {
    var name = ""
    var id = ""
    var added = false
}

My arrays:

var people : [PeopleSelectItem] = []
var selectedPeople : [PeopleSelectItem] = []

I want to remove items from people array if they exist (compare by id) on selectedPeople array.

I tried several array filtering and converting to set but none of them worked. What can I do here?

Thanks!

Teja Nandamuri
  • 11,045
  • 6
  • 57
  • 109
The Cook
  • 1,403
  • 3
  • 17
  • 33
  • 1
    Similar to previous SO Question: http://stackoverflow.com/questions/32439289/how-to-get-list-of-common-elements-of-2-array-in-swift – R Saudlach Aug 23 '16 at 12:03
  • Did you try creating a operator in your model something like `func ==(lhs: PeopleSelectItem, rhs: PeopleSelectItem) -> [PeopleSelectItem] { lhs.id == rhs.id //and filter array }` – rootcoder Aug 23 '16 at 12:13

3 Answers3

9
  • Get an array of all ids in selectedPeople

      let selectedPeopleIDs = selectedPeople.map(\.id)
    
  • Filter the items whose id is not in the array

      let filteredPeople = people.filter { !selectedPeopleIDs.contains($0.id) }
    
vadian
  • 274,689
  • 30
  • 353
  • 361
4

If you know that people equal each other if the id is the same then you can conform your struct to the Equatable protocol and you can use the array filter method.

struct PeopleSelectItem : Equatable {
    var name = ""
    var id = ""
    var added = false
}

func ==(lhs: PeopleSelectItem, rhs: PeopleSelectItem) -> Bool {
    return lhs.id == rhs.id
}

func filterPeople() {
    //swift 2, 3:
    people = people.filter{!selectedPeople.contains($0)}

    //swift older versions:
    people = people.filter{!contains(selectedPeople, $0)}
}
Yannick
  • 3,210
  • 1
  • 21
  • 30
  • instead of using filter function again, is it sensible to create a new operator that returns the filtered result model? – rootcoder Aug 23 '16 at 12:19
1

If people might have a significant amount of entries, performance should be considered. So, instead of searching with an n^2 algorithm, you should make use of Swifts dictionary and the corresponding hash-search to find items.

If Id is unique for people then I would store them in a dictionary like:

    var peopleDict: [String:PeopleSelectItem] = [:]()

You can easily convert from the array you have to this dictionary:

    people.foreach {peopleDict[$0.id] = $0}

With this dictionary it's very easy to delete single entries:

    selectedPeople.foreach {peopleDict.remove($0.id)}

Optionally to switch back to an array for people you just say:

    let filteredPeople = peopleDict.values as [PeopleSelectItem]

Remarks

  1. I assumed, that selectedPeople is smaller then the base of all people. If this is not the case, you should pu selectedPeople in a dictionary.
  2. did I say I like this Spark like api? I think I do so.
  3. I just wrote that code from top of my mind. If it is not completely syntactically correct let me know and I correct it.
jboi
  • 11,324
  • 4
  • 36
  • 43