说我有一个对象:
struct Foo {
let id: Int
let bar: Int
}
现在,我在一个数组中有5个对象:
let foo1 = Foo(id: 1, bar: 1)
let foo2 = Foo(id: 2, bar: 1)
let foo3 = Foo(id: 3, bar: 2)
let foo4 = Foo(id: 4, bar: 3)
let foo5 = Foo(id: 5, bar: 3)
let fooArray = [foo1, foo2, foo3, foo4, foo5]
过滤具有唯一bar
值的foo
对象的干净方法是什么?
// Desired output
let filteredArray = [foo1, foo3, foo4]
假设有几百到几千个物体在任何地方进行迭代。
一种可能的方法是使用Set
,该方法跟踪哪个方法 bar
值已经看到:
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
}
}
正如@hamish正确指出的那样,可以将其缩短为
var seenBarValues = Set<Int>()
let filteredArray = fooArray.filter {
seenBarValues.insert($0.bar).inserted
}
使用
的事实public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element)
返回一个元组,其第一个成员指示元素是否等于在集合中已经存在于新插入的。
我不喜欢被接受的答案。在使用它的闭合外,将设置看起来不合适。我宁愿保留所有内容。有一个CS术语适用,但我不记得它是什么...
我宁愿看到这一点:
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