Skip to content

Instantly share code, notes, and snippets.

@wokalski
Created August 19, 2017 20:14
Show Gist options
  • Save wokalski/7ef031ed647c0cfbdab75c5780a5645c to your computer and use it in GitHub Desktop.
Save wokalski/7ef031ed647c0cfbdab75c5780a5645c to your computer and use it in GitHub Desktop.
Swift version 4.0 (swiftlang-900.0.59 clang-900.0.34.2)
fileprivate func splitOnTheMiddle<T: RandomAccessCollection>(inItems items: T)
-> Optional<(head: T.SubSequence, item: T.Element, tail: T.SubSequence)> where T.IndexDistance == Int, T.Index == Int, T.SubSequence: RandomAccessCollection {
if items.count == 0 {
return .none
}
let lastIndex = items.count - 1
let middleIndex = lastIndex / 2
let head = items.dropLast(lastIndex - middleIndex + 1)
let tail = items.dropFirst(middleIndex + 1)
return (head: head, item: items[middleIndex], tail: tail)
}
fileprivate func recSplit<T: RandomAccessCollection>(inItems items: T, invocationNumber: Int)
-> T.Element? where T.IndexDistance == Int, T.Index == Int, T.SubSequence: RandomAccessCollection {
if invocationNumber == 2 {
return items.first
}
let mid = splitOnTheMiddle(inItems: items)
if let mid = mid {
return recSplit(inItems: mid.head, invocationNumber: invocationNumber + 1)
}
return nil
}
recSplit(inItems: [1, 2, 3], invocationNumber: 0);
@ole
Copy link

ole commented Aug 21, 2017

I would write it like this. If you use the Collection API to do your index calculations, you can get rid of the ... == Int constraints.

fileprivate func splitOnTheMiddle<T: RandomAccessCollection>(inItems items: T)
    -> Optional<(head: T.SubSequence, item: T.Element, tail: T.SubSequence)>
    where T.SubSequence: RandomAccessCollection
{
    // Use isEmpty instead of count.
    // (Performance should be the same for RandomAccessCollection
    // but isEmpty is semantically clearer IMO.)
    guard !items.isEmpty else {
        return .none
    }

    // Use Collection API instead of + and - for index calculations.
    // Allows you to get rid of the ... == Int constraints.
    let middleIndex = items.index(items.startIndex, offsetBy: (items.count - 1) / 2)
    let tailStartIndex = items.index(after: middleIndex)
    let head = items[..<middleIndex]
    let tail = items[tailStartIndex...]
    return (head: head, item: items[middleIndex], tail: tail)
}

PS: My translation of your index math may be off. I haven't checked it very thoroughly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment