1

我编写了以下扩展来从我的数组中删除重复项。

extension Array where Element : Equatable{

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

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

        return result
    }
}

线性阵列

let linearArr = [1,2,2,3]
linearArr.removeDups() // [1,2,3] works well!

多维数组

let multiDimArr : [[Int]] = [[1,2,3], [1,2,3], [1,2 ,4]]
multiDimArr.removeDups() // Error!

类型 [Int] 不符合 Equatable

在这里阅读。答案说使用数组比较==应该有效。它并不总是有效:

作品

if (["1", "2"] == ["1", "2"]){
    print("true")
}

不工作

if ([1, 2] == [1, 2]){ // ERROR!
    print("true")
}

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

这很奇特。我可以比较Strings 数组,但不能比较Ints 数组。

我也看到了这个评论

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

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

总结一下:

  • 数组是等价的吗?我可以使用它们进行比较吗==
  • 为什么比较 Array of Strings 与 Array of Ints不同
  • 如何从多维数组中删除重复项?

我目前正在与Swift 4.0.2

4

2 回答 2

6

数组是等价的吗?我可以使用它们进行比较吗==

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

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

然而,在 Swift 4.1(Xcode 9.3 中可用)中,当它Array<Element>符合. 此更改在更改日志中给出EquatableElementEquatable

斯威夫特 4.1

[...]

  • SE-0143标准库类型Optional, Array, ArraySlice,ContiguousArrayDictionary现在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]]

不幸的是,这确实会导致一些代码重复,但至少您可以在更新到 4.1 时摆脱它。

这个例子不能在 4.0.3 或 4.1 中编译的事实:

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

是由于错误SR-5944造成的——编译器认为它是模棱两可的,因为and (两者都是)的==重载。但是 Swift 应该默认一个数组字面量来解决歧义。IndexSetIndexPathExpressibleByArrayLiteralArray

说:

if [1, 2] as [Int] == [1, 2] {
    print("true")
}

或不导入Foundation解决问题。


最后,值得注意的是,如果类型也是,removeDups()则可以提高的性能,允许它以线性时间而不是二次时间运行:ElementHashable

extension Array where Element : Hashable {

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

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

在 Swift 4.2中,Array也有条件地符合Hashablewhen it Elementis Hashable

斯威夫特 4.2

[...]

  • SE-0143标准库类型Optional, Array, ArraySlice, ContiguousArray, Dictionary, DictionaryLiteral, Range, 和ClosedRange现在Hashable在其元素或绑定类型(视情况而定)符合时符合协议Hashable。这使得综合Hashable实现可用于包含这些类型的存储属性的类型。
于 2018-05-10T16:02:10.600 回答
-2

这是递归可以解决问题的地方。你考虑过递归吗?我打算用实际代码回答这个问题,但我不知道 Swift 的语法。所以,这里有一些伪代码:

function removeDupes() {
    buffer = array;
    foreach this->elements as key => element {             
         if(element is type array) {
              this->elements[key] = element->removeDupes();
         } else {
              if(!this->contains(element)) {
                  buffer->add(element);
              }
         }             
    }
    return buffer;
}

基本上,您想测试元素本身是否为数组。如果是,那么您想调用该数组的 removeDupes() 方法(该方法会依次查找重复项,除非找到另一个数组,否则它将再次调用自己)。

于 2018-05-10T14:55:39.140 回答