我有2个阵列:
var list:Array<Int> = [1,2,3,4,5]
var findList:Array<Int> = [1,3,5]
我想确定list
数组是否包含所有findList
元素。
顺便说一句,元素也可能是String
或其他类型。
怎么做?
我知道Swift提供的contains
方法适用于一个项目。
答案 0 :(得分:43)
您可以使用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)
答案 1 :(得分:7)
考虑以下通用方法:
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上测试)
答案 2 :(得分:6)
您可以使用filter
方法返回findList
中不属于list
的所有元素:
let notFoundList = findList.filter( { contains(list, $0) == false } )
然后检查返回数组的长度是否为零:
let contained = notFoundList.count == 0
请注意,他的解决方案遍历整个findList
数组,因此只要找到非包含元素,它就不会停止。如果您还想知道哪些元素未包含,则应该使用它。
如果您只需要一个布尔值来说明是否包含所有元素,那么 Maxim Shoustin 提供的解决方案会更有效。
答案 3 :(得分:6)
在 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
}
}
您可以看到包含方法here
这只是一个简单的扩展,用于检查您提供的数组是否在当前数组(self)
中答案 4 :(得分:5)
allSatisfy
似乎就是您想要的,假设您无法使元素符合Hashable
并使用其他人提到的集合交集方法:
let containsAll = array.allSatisfy(otherArray.contains)
答案 5 :(得分:4)
作为处理多个元素的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
替代品好得多。
答案 6 :(得分:2)
现在,我可能会使用类似的东西:
let result = list.reduce(true, { $0 ? contains(findList, $1) : $0 })
...但后来我只做了read this article,这可能会让我偏向于这种解决方案。如果没有让它变得完全不可读,你可能会让它变得更有效率,但是它很早就没有我的咖啡。
答案 7 :(得分:2)
使用以下方法扩展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方法。
答案 8 :(得分:2)
这是针对Swift 3更新的Maxim Shoustin's answer:
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
}
答案 9 :(得分:1)
以前的答案似乎都不对。.
考虑:
let a = [2,2]
let b = [1,2,3]
我们不会说b实际上“包含” a,但是如果您的算法基于for循环和swift的内置contains(element:)
或集合,则上述情况将通过。
答案 10 :(得分:1)
我自己使用这套扩展方法。我希望此代码段对您有所帮助:
// 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
}
}
答案 11 :(得分:0)
如果需要确定,则一个数组是另一个数组的subArray。
public extension Array where Element: Equatable {
func isSuperArray(of array: Array<Element>) -> Bool {
guard
count >= array.count,
let indexes = array.first.flatMap(indexes(of:)),
!indexes.isEmpty else {
return false
}
let arraysForComparison = indexes
.compactMap { index -> [Element]? in
guard index + (array.count - 1) <= count else { return nil }
return Array(self[index..<(index + array.count)])
}
return arraysForComparison.contains(array)
}
func isSubArray(of array: Array<Element>) -> Bool {
array.isSuperArray(of: self)
}
private func indexes(of element: Element) -> [Index] {
enumerated()
.filter { element == $0.1 }
.map { index, _ in index }
}
}
用法示例:
let array1 = [1, 2, 3, 4]
let array2 = [2, 3]
print(array1.isSuperArray(of: array2)) // true
print(array2.isSubArray(of: array1)) // true
print(array2.isSuperArray(of: array1)) // false
print(array1.isSubArray(of: array2)) // false