从多维数组中删除重复项 [英] Remove duplicates from a multi-dimensional array

查看:134
本文介绍了从多维数组中删除重复项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了以下扩展名,以从阵列中删除重复项.

I wrote the following extension to remove duplicates from my Array.

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

Type [Int] does not conform to Equatable

我在在此处阅读.答案是使用==进行数组比较应该可以.并非总是如此:

I read here. And the answer says Array comparisons using == should work. It doesn't work all the time:

工程

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

不起作用

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

运算符'=='的不明确使用

Ambiguous use of operator '=='

这很奇怪.我可以比较String的数组,但是不能比较Int s的数组.

This is peculiar. I can compare Array of Strings but can't compare Array of Ints.

我还看到了此评论:

myArray1 == myArray2的原因是NSObject符合Equatable,因此调用-[equals:]进行测试

The reason myArray1 == myArray2 is that NSObject conforms to Equatable, calling -[equals:] to conduct the test

不确定☝️注释是否仍然有效.

Not sure if the ☝️ comment is still valid.

总结:

  • 数组是否相等?我可以使用==
  • 比较它们吗
  • 为什么比较String s的数组与Int s的数组
  • 有何不同?
  • 如何从多维数组中删除重复项?
  • Are arrays equatable? Can I compare them using ==
  • Why is it different for comparing Array of Strings vs. Array of Ints
  • How can I remove duplicates from a multi-dimensional array?

我目前正在使用Swift 4.0.2

推荐答案

数组是否相等?我可以使用==

在Swift 4.1之前,Array不符合Equatable.但是,==的重载将两个数组与Equatable元素进行了比较,这使得它可以进行编译:

Prior to Swift 4.1, Array didn't conform Equatable. There was however an overload of == that compared two arrays with Equatable elements, which is what enabled this to compile:

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

但是,在Swift 4.1(适用于Xcode 9.3)中,当Array<Element>现在符合Equatable时,它的Element符合Equatable的要求.更改日志中给出了 :

However in Swift 4.1 (available with Xcode 9.3), Array<Element> now conforms to Equatable when its Element conforms to Equatable. This change is given in the changelog:

Swift 4.1

[...]

Swift 4.1

[...]

  • SE-0143 现在,标准库类型OptionalArrayArraySliceContiguousArrayDictionary的元素类型符合Equatable时,它们符合Equatable协议.这允许==运算符进行组合(例如,可以将[Int : [Int?]?]类型的两个值与==进行比较),以及使用为Equatable元素类型定义的各种算法,例如index(of:).
  • SE-0143 The standard library types Optional, Array, ArraySlice, ContiguousArray, and Dictionary now conform to the Equatable protocol when their element types conform to Equatable. This allows the == operator to compose (e.g., one can compare two values of type [Int : [Int?]?] with ==), as well as use various algorithms defined for Equatable element types, such as index(of:).

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

Your example with multiDimArr.removeDups() compiles and runs as expected in 4.1, yielding the result [[1, 2, 3], [1, 2, 4]].

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

In Swift 4.0.3, you could hack it by adding another overload of removeDups() for nested arrays:

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时您将能够摆脱它.

This does unfortunately lead to some code duplication, but at least you'll be able to get rid of it when updating to 4.1.

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

The fact that this example doesn't compile in either 4.0.3 or 4.1:

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

是由于错误 SR-5944 引起的–编译器正在考虑将其用于由于IndexSetIndexPath(两者均为ExpressibleByArrayLiteral)的==重载而导致模棱两可.但是,Swift应该将数组文字默认设置为Array,以解决歧义.

is due to the bug SR-5944 – the compiler is considering it to be ambiguous due to == overloads for IndexSet and IndexPath (both of which are ExpressibleByArrayLiteral). But Swift should default an array literal to Array though, resolving the ambiguity.

说:

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

或不导入Foundation即可解决问题.

or not importing Foundation resolves the issue.

最后,值得注意的是,如果Element类型也为Hashable,则removeDups()的性能可以得到改善,从而使其可以线性运行,而不是二次运行:

Finally, it's worth noting that the performance of removeDups() can be improved if the Element type is also Hashable, allowing it to run in linear, rather than quadratic time:

extension Array where Element : Hashable {

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

在这里,我们正在使用一个集合来存储我们已经看到的元素,而忽略了我们已经插入到其中的任何元素.这也使我们可以将filter(_:)用作@Alexander点.

Here we're using a set to store the elements that we've seen, omitting any that we've already inserted into it. This also allows us to use filter(_:), as @Alexander points out.

并且在Swift 4.2中ElementHashable时,也有条件地符合Hashable:

And in Swift 4.2, Array also conditionally conforms to Hashable when its Element is Hashable:

Swift 4.2

[...]

Swift 4.2

[...]

  • SE-0143 现在,标准库类型OptionalArrayArraySliceContiguousArrayDictionaryDictionaryLiteralRangeClosedRange的元素或绑定类型符合Hashable协议(视情况而定)符合Hashable.这使得合成的Hashable实现可用于包含这些类型的存储属性的类型.
  • SE-0143 The standard library types Optional, Array, ArraySlice, ContiguousArray, Dictionary, DictionaryLiteral, Range, and ClosedRange now conform to the Hashable protocol when their element or bound types (as the case may be) conform to Hashable. This makes synthesized Hashable implementations available for types that include stored properties of these types.

这篇关于从多维数组中删除重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆