Say I have an object:
struct Foo {
let id: Int
let bar: Int
}
Now I have 5 of these objects in an array:
let foo1 =
I'm not a fan of the accepted answer. Having the set outside the closure that uses it doesn't seem appropriate. I would rather keep everything contained. There's a CS term that applies but I don't remember what it is...
I would rather see this:
let uniquedBars = fooArray
.reduce(into: (result: [Foo](), set: Set<Int>())) { partial, next in
if partial.set.insert(next.bar).inserted {
partial.result.append(next)
}
}
.result
One possible approach is to use a Set
which keeps track of which
bar
values have already been seen:
var seenBarValues = Set<Int>()
let filteredArray = fooArray.filter { foo in
if seenBarValues.contains(foo.bar) {
// We already had a `Foo` with this `bar` value: skip.
return false
} else {
// First `Foo` with this `bar` value: remember and include.
seenBarValues.insert(foo.bar)
return true
}
}
As @Hamish correctly pointed out, this can be shortened to
var seenBarValues = Set<Int>()
let filteredArray = fooArray.filter {
seenBarValues.insert($0.bar).inserted
}
using the fact that
public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element)
returns a tuple whose first member indicates if an element equal to the newly inserted one was already present in the set.