无法在Swift Array扩展中使用contains

时间:2014-06-06 21:41:52

标签: swift

我正在尝试编写一个简单的数组扩展,它提供了一个独特的'方法。以下是我到目前为止的情况:

extension Array {
  func distinct() -> T[] {
    var rtn = T[]()

    for x in self {
      var containsItem = contains(rtn, x)
      if !containsItem {
        rtn.append(x)
      }
    }
    return rtn
  }
 }

问题在于'包含'声明失败如下:

无法找到'包含'接受提供的参数

我很确定类型约束是正确的。有什么想法吗?

4 个答案:

答案 0 :(得分:13)

Swift 1.x

array中的元素不一定是Equatable,即它们与==不具有可比性。

这意味着您无法为所有可能的数组编写该函数。 Swift不允许您只扩展数组的子集。

这意味着你应该把它写成一个单独的函数(这可能也是contains不是方法的原因。)

let array = ["a", "b", "c", "a"]

func distinct<T: Equatable>(array: [T]) -> [T] {
    var rtn = [T]()

    for x in array {
        var containsItem = contains(rtn, x)
        if !containsItem {
            rtn.append(x)
        }
    }
    return rtn
}

distinct(array) // ["a", "b", "c"]

Swift 2 / Xcode 7(Beta)的更新

Swift 2支持限制对协议实现子集的扩展,因此现在允许以下内容:

let array = ["a", "b", "c", "a"]

extension SequenceType where Generator.Element: Comparable {
    func distinct() -> [Generator.Element] {
        var rtn: [Generator.Element] = []

        for x in self {
            if !rtn.contains(x) {
                rtn.append(x)
            }
        }
        return rtn
    }
}

array.distinct() // ["a", "b", "c"]

请注意Apple如何使用相同的语法添加SequenceType.contains

答案 1 :(得分:5)

终于找到了如何做到这一点:

extension Array {
    func contains<T : Equatable>(obj: T) -> Bool {
        return self.filter({$0 as? T == obj}).count > 0
    }

    func distinct<T : Equatable>(_: T) -> T[] {
        var rtn = T[]()

        for x in self {
            if !rtn.contains(x as T) {
                rtn += x as T
            }
        }

        return rtn
    }
}

使用/测试:

let a = [ 0, 1, 2, 3, 4, 5, 6, 1, 2, 3 ]

a.contains(0)
a.contains(99)

a.distinct(0)

不幸的是,我无法找到一种方法来做到这一点,而无需指定随后被忽略的参数。它唯一的原因就是调用正确的形式。这种方法对distinct的主要优点似乎是它没有将像distinct这样的常用术语转储到全局命名空间中。对于包含情况,它看起来更自然。

答案 2 :(得分:2)

另一个解决方案是使用find(Array:[T],​​obj:T)函数。它将返回一个可选的Int,所以你可以做的是

if let foundResult = find(arr, obj) as Int
{
     //obj is contained in arr
} else
{
     //obj is not contained in arr.
}

答案 3 :(得分:2)

从Swift 2开始,这可以通过协议扩展方法来实现, 例如在符合SequenceType顺序的所有类型上 元素符合Equatable

extension SequenceType where Generator.Element : Equatable {

    func distinct() -> [Generator.Element] {
        var rtn : [Generator.Element] = []

        for elem in self {
            if !rtn.contains(elem) {
                rtn.append(elem)
            }
        }

        return rtn
    }
}

示例:

let items = [1, 2, 3, 2, 3, 4]
let unique = items.distinct()
print(unique) // [1, 2, 3, 4]

如果元素被进一步限制为Hashable那么你 可以利用Set类型:

extension SequenceType where Generator.Element : Hashable {

    func distinct() -> [Generator.Element] {
        return Array(Set(self))
    }
}