我有两个数组:
var list:Array<Int> = [1,2,3,4,5]
var findList:Array<Int> = [1,3,5]
我希望确定list
数组是否包含所有findList
元素。
顺便说一下,元素也可能是String
或其他类型。
如何做到这一点?
我知道Swift提供了一个contains
方法,可以用于一个项。
不必自己迭代数组并进行筛选,您可以使用NSSet
来为您完成所有工作。
var list:Array<Int> = [1,2,3,4,5]
var findList:Array<Int> = [1,3,5]
let listSet = NSSet(array: list)
let findListSet = NSSet(array: findList)
let allElemtsEqual = findListSet.isSubsetOfSet(otherSet: listSet)
NSSet
检查是否包含任何对象比数组快得多,实际上这就是它的设计目的。
编辑: 使用 Swift 的内置 Set
。
let list = [1,2,3,4,5]
let findList = [1,3,5]
let listSet = Set(list)
let findListSet = Set(findList)
//**Swift 4.2 and Above**
let allElemsContained = findListSet.isSubset(of: listSet)
//below versions
//let allElemsContained = findListSet.isSubsetOf(listSet)
listSet == findListSet
的值为 false。 - orkodenisSubsetOfSet(_ otherSet:)
。谢谢。 - orkodenlet list = [1,2,3,4,5]
和 let findList = [1,3,3,5]
,这段代码是否会得到预期结果?当使用 Set
时,findList
是 list
的子集,但是当仅比较数组时则不是。 - koenallSatisfy
似乎是你想要的,假设你不能符合元素 Hashable
并使用其他人提到的集合交集方法:
let containsAll = subArray.allSatisfy(largerArray.contains)
自从 Swift 4.2 版本以后,你可以写:
extension Array where Element: Equatable {
func satisfy(array: [Element]) -> Bool {
return self.allSatisfy(array.contains)
}
}
否则,对于 Swift 3、Swift 4,您可以编写以下代码:
extension Array where Element: Equatable {
func contains(array: [Element]) -> Bool {
for item in array {
if !self.contains(item) { return false }
}
return true
}
}
您可以在此处查看:
这只是一个简单的扩展,检查您提供的数组是否在当前数组(self)中。
Sequence.contains(element)
处理多个元素的补充,添加以下扩展:public extension Sequence where Element : Hashable {
func contains(_ elements: [Element]) -> Bool {
return Set(elements).isSubset(of:Set(self))
}
}
使用:
list.contains(findList)
由于使用了Set
/Hashable
,因此其性能比Equatable
的替代方案要好得多。
func arrayContainsArray<S : SequenceType where S.Generator.Element : Equatable>
(src:S, lookFor:S) -> Bool{
for v:S.Generator.Element in lookFor{
if contains(src, v) == false{
return false
}
}
return true
}
findList
测试
var listAsInt:Array<Int> = [1,2,3,4,5]
var findListAsInt:Array<Int> = [1,3,5]
var result = arrayContainsArray(listAsInt, findListAsInt) // true
listAsInt:Array<Int> = [1,2,3,4,5]
findListAsInt:Array<Int> = [1,3,5,7,8,9]
result = arrayContainsArray(listAsInt, findListAsInt) // false
var listOfStr:Array<String> = ["aaa","bbb","ccc","ddd","eee"]
var findListOfStr:Array<String> = ["bbb","ccc","eee"]
result = arrayContainsArray(listOfStr, findListOfStr) // true
listOfStr:Array<String> = ["aaa","bbb","ccc","ddd","eee"]
findListOfStr:Array<String> = ["bbb","ccc","eee","sss","fff","ggg"]
result = arrayContainsArray(listOfStr, findListOfStr) // false
(在Beta7上测试过)
filter
方法返回findList
中所有不在list
中的元素:let notFoundList = findList.filter( { contains(list, $0) == false } )
然后检查返回的数组长度是否为零:
let contained = notFoundList.count == 0
findList
数组,因此它不会在找到非包含元素后立即停止。如果您还想知道哪些元素未包含,则应使用它。现在,我可能会使用类似以下的东西:
let result = list.reduce(true, { $0 ? contains(findList, $1) : $0 })
...但我刚刚读了这篇文章,可能会让我对这种解决方案有所偏见。你可能可以在不完全难以理解的情况下使其更加高效,但现在还很早,我还没喝咖啡。
扩展Array
,添加以下方法:
extension Array {
func contains<T where T : Equatable>(obj: T) -> Bool {
return self.filter({$0 as? T == obj}).count > 0
}
func isEqualTo< T : Equatable> (comparingArray : [T]) -> Bool {
if self.count != comparingArray.count {
return false
}
for e in comparingArray {
if !self.contains(e){
return false
}
}
return true
}
}
您可以像这样使用它:
if selectedDates.isEqualTo(originalDates) {
//Arrays the same hide save button
} else {
//Arrays not the same, show Save & Discard Changes Button (if not shown)
}
感谢 @David Berry 提供的 contain 方法。
之前的答案似乎都不正确。
考虑以下内容:
let a = [2,2]
let b = [1,2,3]
我们不会说 b 实际上“包含”a,但是如果您的算法基于 for-loop 和 Swift 内置的 contains(element:)
或者一个集合,那么上述情况将通过。
我使用这组扩展方法。我希望这个代码片段能够帮助你:
// Array + CommonElements.swift
import Foundation
public extension Array where Element: Hashable {
func set() -> Set<Array.Element> {
return Set(self)
}
func isSubset(of array: Array) -> Bool {
self.set().isSubset(of: array.set())
}
func isSuperset(of array: Array) -> Bool {
self.set().isSuperset(of: array.set())
}
func commonElements(between array: Array) -> Array {
let intersection = self.set().intersection(array.set())
return intersection.map({ $0 })
}
func hasCommonElements(with array: Array) -> Bool {
return self.commonElements(between: array).count >= 1 ? true : false
}
}
Equatable
符合性的解决方案,这会产生>= O(n)的性能。最好使用具有Hashable
符合性的Set
,在许多情况下比使用Equatable
快一个数量级。我已经添加了以下类似的“包含”扩展。 - David James