簡體   English   中英

如何在Swift中創建唯一對象列表數組

[英]How to create array of unique object list in Swift

我們如何在Swift語言中創建唯一的對象列表,例如Objective-C中的NSSetNSMutableSet

從Swift 1.2(Xcode 6.3 beta)開始,Swift具有本機集合類型。 從發行說明中:

包含一個新的Set數據結構,該結構提供具有全值語義的獨特元素的通用集合。 它與NSSet橋接,提供類似於ArrayDictionary

以下是一些簡單的用法示例:

// Create set from array literal:
var set = Set([1, 2, 3, 2, 1])

// Add single elements:
set.insert(4)
set.insert(3)

// Add multiple elements:
set.unionInPlace([ 4, 5, 6 ])
// Swift 3: set.formUnion([ 4, 5, 6 ])

// Remove single element:
set.remove(2)

// Remove multiple elements:
set.subtractInPlace([ 6, 7 ])
// Swift 3: set.subtract([ 6, 7 ])

print(set) // [5, 3, 1, 4]

// Test membership:
if set.contains(5) {
    print("yes")
}

但是還有更多可用的方法。

更新:現在,集合也記錄在Swift文檔的“集合類型”一章中。

您可以在Swift中使用任何Objective-C類:

var set = NSMutableSet()
set.addObject(foo)

Swift沒有集合的概念。 在Swift中使用NSMutableSet可能比使用包含偽值的Dictionary慢。 您可以這樣做:

var mySet: Dictionary<String, Boolean> = [:]
mySet["something"]= 1

然后只需遍歷鍵。

我建立了一個類似於內置ArrayDictionary的廣泛Set類型-這是博客文章一和二以及GitHub存儲庫:

extension Array where Element: Hashable {
    var setValue: Set<Element> {
        return Set<Element>(self)
    }
}

let numbers = [1,2,3,4,5,6,7,8,9,0,0,9,8,7]
let uniqueNumbers = numbers.setValue    // {0, 2, 4, 9, 5, 6, 7, 3, 1, 8}

let names = ["John","Mary","Steve","Mary"]
let uniqueNames = names.setValue    // {"John", "Mary", "Steve"}

我以為帶有內部Dictionary的結構是應該走的路。 我才剛剛開始使用它,所以它還不完整,我對性能還不了解。

struct Set<T : Hashable>
{
    var _items : Dictionary<T, Bool> = [:]

    mutating func add(newItem : T) {
        _items[newItem] = true
    }

    mutating func remove(newItem : T) {
        _items[newItem] = nil
    }

    func contains(item: T) -> Bool {
        if _items.indexForKey(item) != nil { return true } else { return false }
    }

    var items : [T] { get { return [T](_items.keys) } }
    var count : Int { get { return _items.count } }
}

實際上,您可以非常輕松地創建Set對象(與GoZoner矛盾的是,有一個內置的contains方法):

class Set<T : Equatable> {
    var items : T[] = []

    func add(item : T) {
        if !contains(items, {$0 == item}) {
            items += item
        }
    }
}

您甚至可能想要聲明一個自定義運算符:

@assignment @infix func += <T : Equatable> (inout set : Set<T>, items : T[]) -> Set<T> {
    for item in items {
        set.add(item)
    }
    return set
}

在這種情況下,關鍵始終是如何比較對象以及將哪些類型的對象放入集合中。 基於鍵類型(字符串,整數,雙精度,布爾型,無值枚舉或可散列)的限制,使用Set對象為詞典鍵的Swift字典可能會成為問題。

如果可以在對象類型上定義哈希函數 ,則可以使用字典。 如果對象是可排序的 ,則可以定義樹。 如果對象僅與==具有可比性,那么您將需要遍歷set元素以檢測預先存在的對象。

// When T is only Equatable
class Set<T: Equatable> {
  var items = Array<T>()

  func hasItem (that: T) {
   // No builtin Array method of hasItem... 
   //   because comparison is undefined in builtin Array   
   for this: T in items {
     if (this == that) {
       return true
     }
   }
   return false
  }

  func insert (that: T) {
    if (!hasItem (that))
      items.append (that)
  }
}

上面是建立Swift Set一個例子; 該示例使用的對象僅是Equatable -盡管這是一種常見情況,但不一定會導致有效的Set實現(O(N)搜索復雜度-以上是示例)。

所以我認為用數組創建Set是一個糟糕的主意-O(n)是該Set的時間復雜度。

我已經整理好了一個使用字典的Set: https : //github.com/evilpenguin/Swift-Stuff/blob/master/Set.swift

我寫了一個函數來解決這個問題。

public func removeDuplicates<C: ExtensibleCollectionType where C.Generator.Element : Equatable>(aCollection: C) -> C {
    var container = C()

    for element in aCollection {
        if !contains(container, element) {
            container.append(element)
        }
    }

    return container
}

要使用它,只需將包含重復元素的數組傳遞給此函數。 然后它將返回一個保證唯一性的數組。

如果願意,還可以傳遞DictionaryString或任何符合ExtensibleCollectionType協議的內容。

從NSObject派生的類的特殊情況

鑒於NSObject中默認的Equitable(&Hashable)一致性基本上是垃圾,因此最好確保提供適當的

static func == (lhs: YourClassDerivedFromNSObject, rhs: YourClassDerivedFromNSObject) -> Bool {

實現,以免您想刪除插入到Set中的重復項

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM