从多维数组中删除重复项

Hon*_*ney 1 arrays value-type swift equatable

我写了以下扩展名来删除我的数组中的重复项.

extension Array where Element : Equatable{

    func removeDups() -> [Element]{
        var result = [Element]()

        for element in self{
            if !result.contains(element){
                result.append(element)
            }
        }

        return result
    }
}
Run Code Online (Sandbox Code Playgroud)

线性阵列

let linearArr = [1,2,2,3]
linearArr.removeDups() // [1,2,3] works well!
Run Code Online (Sandbox Code Playgroud)

多维数组

let multiDimArr : [[Int]] = [[1,2,3], [1,2,3], [1,2 ,4]]
multiDimArr.removeDups() // Error!
Run Code Online (Sandbox Code Playgroud)

类型[Int]不符合Equatable

我读到这里.答案说使用阵列比较==应该可行.它不能一直工作:

作品

if (["1", "2"] == ["1", "2"]){
    print("true")
}
Run Code Online (Sandbox Code Playgroud)

不行

if ([1, 2] == [1, 2]){ // ERROR!
    print("true")
}
Run Code Online (Sandbox Code Playgroud)

运算符'=='的模糊使用

这很特别.我可以比较数组的Strings但不能比较数组的Ints.

我也看到了这个评论:

原因myArray1 == myArray2NSObject符合Equatable,要求-[equals:]进行测试

不确定☝️评论是否仍然有效.

总结一下:

  • 数组是否相等?我可以用它来比较它们吗?==
  • 为什么比较StringS的数组与Ints的数组不同
  • 如何从多维数组中删除重复项?

我正在和我一起工作 Swift 4.0.2

Ham*_*ish 6

数组是否相等?我可以用它来比较它们吗?==

在Swift 4.1之前,Array没有符合Equatable.然而,==有两个数组与Equatable元素进行比较的重载,这使得它能够编译:

if ["1", "2"] == ["1", "2"] { // using <T : Equatable>(lhs: [T], rhs: [T]) -> Bool
    print("true")
}
Run Code Online (Sandbox Code Playgroud)

但是在Swift 4.1(Xcode 9.3中可用)中,Array<Element>现在符合Equatable它的Element符合性Equatable.更改日志中给出了此更改:

Swift 4.1

[...]

  • SE-0143标准库类型Optional,Array,ArraySlice,ContiguousArray,和Dictionary现在符合Equatable协议时,他们的元素类型符合Equatable.这允许==操作者以构成(例如,一个可以比较型的两个值[Int : [Int?]?]==),以及用于定义各种算法Equatable元件类型,如index(of:).

您的示例multiDimArr.removeDups()在4.1中按预期编译和运行,产生结果[[1, 2, 3], [1, 2, 4]].

在Swift 4.0.3中,您可以通过removeDups()为嵌套数组添加另一个重载来破解它:

extension Array {
  func removeDups<T : Equatable>() -> [Element] where Element == [T] {

    var result = [Element]()

    for element in self{
      if !result.contains(where: { element == $0 }) {
        result.append(element)
      }
    }

    return result
  }
}

let multiDimArr = [[1, 2, 3], [1, 2, 3], [1, 2, 4]]
print(multiDimArr.removeDups()) // [[1, 2, 3], [1, 2, 4]]
Run Code Online (Sandbox Code Playgroud)

不幸的是,这会导致一些代码重复,但至少在更新到4.1时你将能够摆脱它.

此示例无法在4.0.3或4.1中编译的事实:

if [1, 2] == [1, 2] { // error: Ambiguous use of operator '=='
    print("true")
}
Run Code Online (Sandbox Code Playgroud)

是由于SR-5944的错误- 编译器认为它由于和(两者都是)的==重载而不明确.但Swift应该默认一个数组文字,解决歧义.IndexSetIndexPathExpressibleByArrayLiteralArray

说:

if [1, 2] as [Int] == [1, 2] {
    print("true")
}
Run Code Online (Sandbox Code Playgroud)

或不导入Foundation解决问题.


最后,值得注意的是,removeDups()如果Element类型也可以改善性能Hashable,允许它以线性而非二次时间运行:

extension Array where Element : Hashable {

  func removeDups() -> [Element] {
    var uniquedElements = Set<Element>()
    return filter { uniquedElements.insert($0).inserted }
  }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们使用一个集合来存储我们已经看到的元素,省略我们已经插入的元素.这也允许我们使用filter(_:),正如@Alexander指出的那样.

在斯威夫特4.2,Array也有条件地符合Hashable当其ElementHashable:

Swift 4.2

[...]

  • SE-0143标准库类型Optional,Array,ArraySlice,ContiguousArray,Dictionary,DictionaryLiteral,Range,和ClosedRange现在符合Hashable协议时其元件或结合类型(视情况而定)符合Hashable.这使得合成Hashable实现可用于包含这些类型的存储属性的类型.