如何在Swift中创建唯一对象列表数组

时间:2014-06-04 17:48:24

标签: swift nsset

我们如何使用Swift语言创建唯一的对象列表,如NSSet& Objective-C中的NSMutableSet

11 个答案:

答案 0 :(得分:50)

从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文档的"Collection Types"章节中也记录了这些集。

答案 1 :(得分:14)

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

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

答案 2 :(得分:10)

Swift没有集合的概念。在Swift中使用NSMutableSet可能比使用保存虚拟值的Dictionary慢。你可以这样做:

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

然后只是遍历键。

答案 3 :(得分:9)

我构建了一个类似于内置SetArray的广泛Dictionary类型 - 这里有博客文章第一和第二个以及一个GitHub存储库:

答案 4 :(得分:7)

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

答案 5 :(得分:4)

我认为带有内部词典的结构将是最佳选择。我刚刚开始使用它,所以它还不完整,我对性能还不了解。

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

答案 6 :(得分:3)

你实际上可以很容易地创建一个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
}

答案 7 :(得分:2)

在这种情况下,关键因素是如何比较对象以及进入Set的对象类型。使用Swift字典,其中Set对象是字典键,可能是基于对键类型(String,Int,Double,Bool,无值枚举或hashable)的限制的问题。

如果您可以在对象类型上定义哈希函数,则可以使用词典。 如果对象是可订购的,则可以定义树。 如果对象仅与== 相当,那么您需要迭代设置元素以检测预先存在的对象。

// 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)搜索复杂性 - 以上是一个示例)

答案 8 :(得分:1)

所以我认为用数组创建一个Set是一个糟糕的主意--O(n)是该集合的时间复杂度。

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

答案 9 :(得分:1)

我写了一个函数来解决这个问题。

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协议的内容。

答案 10 :(得分:0)

从NSObject派生的类的特殊情况

鉴于NSObject中默认的Equitable(和Hashable)一致性基本上是垃圾,您最好确保提供正确的

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

实现,以免您想插入插入的重复项 设置