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

时间:2014-09-07 21:34:58

标签: ios arrays swift

我有2个阵列:

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

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

顺便说一句,元素也可能是String或其他类型。

怎么做?

我知道Swift提供的contains方法适用于一个项目。

12 个答案:

答案 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