2017-03-01 75 views
0

說,我有一個對象:通過獨特的字典來過濾字典數組清潔路值

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] 

會是一個什麼乾淨的過濾方式foo具有唯一bar值的對象?

// Desired output 
let filteredArray = [foo1, foo3, foo4] 

假設從幾百到幾千個對象有任何地方要迭代。

+0

如何使用過濾器是這樣的: 'fooArray.filter {($ 0.bar.contains(搜索欄))}' – rmp

+0

你的問題的標題和正文似乎有所不同 - 你有字典或數組一系列結構? – Hamish

+0

我有一個結構數組,雖然這個問題的答案不適用於結構類型。如果您覺得它很混亂,請隨意編輯標題以使其更符合語義,但我不覺得自己有更好的標題。 – Aaron

回答

3

一種可能的方法是使用一個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) 

返回一個元組,該元組的第一個成員指示是否有一個元素等於 到新插入的元素已經存在於集合中。

+1

或者你可以說'fooArray.filter {seenBarValues.insert($ 0.bar).inserted} :) :) – Hamish

+0

@Hamish:你說得對(一如既往)! –

+0

這些都是很棒的解決方案。謝謝 – Aaron