如何确定一个数组是否包含Swift中另一个数组的所有元素?

我有2个数组:

var list:Array<Int> = [1,2,3,4,5] var findList:Array<Int> = [1,3,5] 

我想确定list数组是否包含所有findList元素。

顺便说一下,元素也可以是String或其他types。

怎么做?

我知道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) let allElemsContained = findListSet.isSubsetOf(listSet) 

考虑下面的通用方法:

 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


testing

 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上testing)

您可以使用filter方法返回不在listfindList所有元素:

 let notFoundList = findList.filter( { contains(list, $0) == false } ) 

然后检查返回数组的长度是否为零:

 let contained = notFoundList.count == 0 

请注意,他的解决scheme遍历整个findList数组,所以它不会停止,只要find一个不包含的元素。 如果您还想知道哪些元素不包含,应该使用它。

如果您只需要一个布尔值来表示是否包含所有元素,那么Maxim Shoustin提供的解决scheme就更有效率。

Swift 3中你可以这样写:

 extension Array where Element: Equatable { func contains(array: [Element]) -> Bool { for item in array { if !self.contains(item) { return false } } return true } } 

你可以在这里看到包含的方法

这只是一个简单的扩展,检查你给出的数组是否在当前数组(self)

现在,我可能会使用像这样的东西:

 let result = list.reduce(true, { $0 ? contains(findList, $1) : $0 }) 

…但后来我读了这篇文章 ,这可能会偏向我这种解决scheme。 你也许可以让这个效率更高,而不是让它变得完全不可读,但是现在还为时过早,而且我还没有喝过咖啡。

使用以下方法扩展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大声喊出包含的方法。

这是Maxim Shoustin的答案更新了Swift 3:

 func arrayContainsArray<S : Sequence> (src:S, lookFor:S) -> Bool where S.Iterator.Element : Equatable{ for v:S.Iterator.Element in lookFor{ if src.contains(v) == false{ return false } } return true } 
 var check = true for i in findList { if list.contains(i) { check = check && true } else { check = false } } 

这工作得很好,只要使用.operator不是必需的。

作为处理多个元素的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替代方法要好得多。