The Cook
The Cook

Reputation: 1443

How to remove common items from two struct arrays in Swift

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!

Upvotes: 1

Views: 1660

Answers (3)

vadian
vadian

Reputation: 285069

  • 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) }
    

Upvotes: 9

jboi
jboi

Reputation: 11892

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.

Upvotes: 1

Yannick
Yannick

Reputation: 3278

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)}
}

Upvotes: 4

Related Questions