Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array contains a complete subarray

Tags:

arrays

swift

In Swift how can I check whether an array contains a given subarray in its entirety? E.g., is there a contains function that works like this:

let mainArray = ["hello", "world", "it's", "a", "beautiful", "day"]
contains(mainArray, ["world", "it's"])   // would return true
contains(mainArray, ["world", "it"])   // would return false
contains(mainArray, ["world", "a"])   // would return false - not adjacent in mainArray
like image 639
Daniel Avatar asked May 24 '16 10:05

Daniel


2 Answers

You can do it with higher-level functions, like this:

func indexOf(data:[String], _ part:[String]) -> Int? {
    // This is to prevent construction of a range from zero to negative
    if part.count > data.count {
        return nil
    }

    // The index of the match could not exceed data.count-part.count
    return (0...data.count-part.count).indexOf {ind in
        // Construct a sub-array from current index,
        // and compare its content to what we are looking for.
        [String](data[ind..<ind+part.count]) == part
    }
}

This function returns the index of the first match, if any, or nil otherwise.

You can use it as follows:

let mainArray = ["hello", "world", "it's", "a", "beautiful", "day"]
if let index = indexOf(mainArray, ["world", "it's"]) {
    print("Found match at \(index)")
} else {
    print("No match")
}

Editing in as an extension to a generic array...

This can now be used for any homogeneous array of Equatable types.

extension Array where Element : Equatable {
    func indexOfContiguous(subArray:[Element]) -> Int? {

        // This is to prevent construction of a range from zero to negative
        if subArray.count > self.count {
            return nil
        }

        // The index of the match could not exceed data.count-part.count
        return (0...self.count-subArray.count).indexOf { ind in
            // Construct a sub-array from current index,
            // and compare its content to what we are looking for.
            [Element](self[ind..<ind+subArray.count]) == subArray
        }
    }
}
like image 144
Sergey Kalinichenko Avatar answered Oct 05 '22 02:10

Sergey Kalinichenko


As far as I know, such a function does not exist. But you can add the functionality with following extension:

extension Array where Element: Equatable {
    func contains(subarray: [Element]) -> Bool {
        guard subarray.count <= count else { return false }
    
        for idx in 0 ... count - subarray.count {
            let start = index(startIndex, offsetBy: idx)
            let end = index(start, offsetBy: subarray.count)
            if Array(self[start ..< end]) == subarray { return true }
        }        
        return false
    }
}

Once the extension is added to your project, you can just call:

mainArray.contains(["world", "it's"]) // true
mainArray.contains(["world", "it"])   // false
mainArray.contains(["it's", "world"]) // false

let array2 = ["hello", "hello", "world"]
array2.contains(["hello", "world"]) // true
[1, 1, 1, 2].contains(subarray: [1, 1, 2]) // true
like image 41
Daniel Avatar answered Oct 05 '22 00:10

Daniel