Reputation: 1509
I'm trying to write a function that returns a Collection
Slice
, for the first occurrence of a given subsequence.
I've managed to write it as an Array
extension, since I know that the return type would be ArraySlice<Element>
, but I'm having trouble figuring out what the appropriate concrete output would be to make it a general function for Collection
extension Array where Element: Comparable {
func firstOccuranceOf(subsequence: [Element]) -> ArraySlice<Element>? {
guard !subsequence.isEmpty else {
return nil
}
guard let startIndex = self.firstIndexOf(subsequence: subsequence) else {
return nil
}
let endIndex = self.index(startIndex, offsetBy: subsequence.count - 1)
return self[startIndex...endIndex]
}
}
TL;DR: How do I re-write the function above as a extension Collection
?
Upvotes: 1
Views: 66
Reputation: 18591
First, let's fix firstOccuranceOf(subsequence:)
as defined on Array
:
//Only `Equatable` is needed
extension Array where Element: Equatable {
func firstOccurence(of subsequence: [Element]) -> ArraySlice<Element>? {
let subsequenceEndIndex = subsequence.endIndex.advanced(by: -1)
let lastPossibleFirstIndex = endIndex.advanced(by: -subsequenceEndIndex)
for i in indices where i < lastPossibleFirstIndex {
let range = i...i.advanced(by: subsequenceEndIndex)
if Array(self[range]) == subsequence {
return self[range]
}
}
return nil
}
}
It gives:
Array(1...10).firstOccurence(of: [6, 300]) //nil
Array(1...10).firstOccurence(of: [6, 7]) //[6, 7]
Array(1...6).firstOccurence(of: [6, 7]) //nil
let array: [Int] = []
array.firstOccurence(of: [6, 7]) //nil
array.firstOccurence(of: []) //nil
For collections in general:
extension Collection where Self: RandomAccessCollection, Element: Equatable {
func firstOccurence(of subsequence: Self) -> Self.SubSequence? {
let subCount = subsequence.count
for i in indices where distance(from: i, to: endIndex) >= subCount {
let subseq = self.suffix(distance(from: i, to: endIndex)).prefix(subCount)
if Array(subseq) == Array(subsequence) {
return subseq
}
}
return nil
}
}
Upvotes: 0
Reputation: 54735
You just need to declare the return type as Self.SubSequence?
. You'll also need to define the firstIndex(of:)
method for Collection
s that you use in your Array
extension. I've defined it just to be able to compile the code, but feel free to change the implementation if your logic was different.
extension Collection where Element: Comparable {
func firstIndex(of subsequence: Self) -> Index? {
guard let firstElement = subsequence.first else { return nil }
return self.firstIndex(of: firstElement)
}
func firstOccurence(of subsequence: Self) -> Self.SubSequence? {
guard !subsequence.isEmpty else { return nil }
guard let startIndex = firstIndex(of: subsequence) else { return nil }
let endIndex = index(startIndex, offsetBy: subsequence.count - 1)
return self[startIndex...endIndex]
}
}
Upvotes: 2