如何确定一个数组是否包含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
方法返回不在list
的findList
所有元素:
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
替代方法要好得多。