可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have 2 arrays:
var list:Array<Int> = [1,2,3,4,5] var findList:Array<Int> = [1,3,5]
I want to determine if list
Array contains all findList
elements.
By the way, elements might be String
as well or other type.
How to do that?
I know that Swift provides contains
method that works with one item.
回答1:
Instead of iterating through arrays and doing filtering yourself, you can use NSSet
to do all the work for you.
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
is a lot faster than arrays at checking if it contains any object. In fact it's what it's designed for.
Edit: Using Swift's built-in 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)
回答2:
Consider following generic method:
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 }
The advantage - method stops after 1st fail and do not continue over findList
Tests
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
(tested on Beta7)
回答3:
You can use the filter
method to return all elements of findList
which are not in list
:
let notFoundList = findList.filter( { contains(list, $0) == false } )
then check if the length of the returned array is zero:
let contained = notFoundList.count == 0
Note that his solution traverses the entire findList
array, so it doesn't stop as soon as a non contained element is found. It should be used if you also want to know which elements are not contained.
If you just need a boolean stating whether all elements are contained or not, then the solution provided by Maxim Shoustin is more efficient.
回答4:
In Swift 3 you can write this:
extension Array where Element: Equatable { func contains(array: [Element]) -> Bool { for item in array { if !self.contains(item) { return false } } return true } }
You can see the contains method here
This is just a simple extension that check if the array that you give is in the current array (self)
回答5:
Right now, I'd probably use something like:
let result = list.reduce(true, { $0 ? contains(findList, $1) : $0 })
...but then I did just read this article, which might be biasing me towards this kind of solution. You could probably make this more efficient without making it completely unreadable, but it's early and I've not had my coffee.
回答6:
Extend the Array
with the following methods:
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 } }
An example of how you can use it like this:
if selectedDates.isEqualTo(originalDates) { //Arrays the same hide save button } else { //Arrays not the same, show Save & Discard Changes Button (if not shown) }
Shout out to @David Berry for the contain method.
回答7:
This is Maxim Shoustin's answer updated for 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 }
回答8:
As a complement to Sequence.contains(element)
handling multiple elements, add this extension:
public extension Sequence where Element : Hashable { func contains(_ elements: [Element]) -> Bool { return Set(elements).isSubset(of:Set(self)) } }
Used:
list.contains(findList)
Since this uses Set
/Hashable
it performs much better than Equatable
alternatives.
回答9:
var check = true for i in findList { if list.contains(i) { check = check && true } else { check = false } }
This works perfectly fine, as long as, the use of .operator is not required.