从多维数组中删除重复项 [英] Remove duplicates from a multi-dimensional array
问题描述
我编写了以下扩展名,以从阵列中删除重复项.
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 String
s but can't compare Array of Int
s.
我还看到了此评论:
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
String
s vs. Array ofInt
s - 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 现在,标准库类型
Optional
,Array
,ArraySlice
,ContiguousArray
和Dictionary
的元素类型符合Equatable
时,它们符合Equatable
协议.这允许==
运算符进行组合(例如,可以将[Int : [Int?]?]
类型的两个值与==
进行比较),以及使用为Equatable
元素类型定义的各种算法,例如index(of:)
.
- SE-0143 The standard library types
Optional
,Array
,ArraySlice
,ContiguousArray
, andDictionary
now conform to theEquatable
protocol when their element types conform toEquatable
. 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 forEquatable
element types, such asindex(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 引起的–编译器正在考虑将其用于由于IndexSet
和IndexPath
(两者均为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中,Element
为Hashable
时,也有条件地符合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 现在,标准库类型
Optional
,Array
,ArraySlice
,ContiguousArray
,Dictionary
,DictionaryLiteral
,Range
和ClosedRange
的元素或绑定类型符合Hashable
协议(视情况而定)符合Hashable
.这使得合成的Hashable
实现可用于包含这些类型的存储属性的类型.
- SE-0143 The standard library types
Optional
,Array
,ArraySlice
,ContiguousArray
,Dictionary
,DictionaryLiteral
,Range
, andClosedRange
now conform to theHashable
protocol when their element or bound types (as the case may be) conform toHashable
. This makes synthesizedHashable
implementations available for types that include stored properties of these types.
这篇关于从多维数组中删除重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!