How to determine if one array contains all elements of another array in Swift?

后端 未结 12 1107
梦如初夏
梦如初夏 2020-12-13 17:47

I have 2 arrays:

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

I want to determine if list A

相关标签:
12条回答
  • 2020-12-13 18:01

    I use this set of extended methods myself. I hope this code snippet helps:

    
    //  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
        }
    }
    
    0 讨论(0)
  • 2020-12-13 18:01

    If you need to determine, that one array is subArray of another.

    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 }
        }
    }
    

    Example of usage:

    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
    
    0 讨论(0)
  • 2020-12-13 18:05

    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.

    0 讨论(0)
  • 2020-12-13 18:06

    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.

    0 讨论(0)
  • 2020-12-13 18:07

    None of the previous answers seem to be right.

    consider:

    let a = [2,2]
    let b = [1,2,3]
    

    we wouldn't say that b actually "contains" a, but if your algorithm is based on for-loop & swift's built-in contains(element:) or a set, the above case would pass.

    0 讨论(0)
  • 2020-12-13 18:08

    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.

    0 讨论(0)
提交回复
热议问题