[swift-evolution] [Proposal] Add Binary Search functions to SequenceType
Dave Abrahams
dabrahams at apple.com
Fri Apr 29 16:26:03 CDT 2016
on Thu Apr 28 2016, Jeff Hajewski <swift-evolution at swift.org> wrote:
> Dave - I think it boils down to a gap in communication. We were under the
> impression that the goal was a pure extension of CollectionType, without making
> any requirements on Generator.Element (i.e., your requiring it to be
> comparable), where binary search, lower bound, and upper bound all work with the
> same unary predicate.
> Of course, as you demonstrated, it is trivial to implement when
> Generator.Element is Comparable, but if you relax that requirement it
> is not possible to create a set of functions (binary search, lower
> bound, upper bound) that all take the same unary predicate.
I'm sorry if I gave you the wrong impression. What I posted was exactly
what I had in mind.
> We ultimately came up with a slightly different approach, implementing
> binary search similar to your example, but a different take on lower
> bound, upper bound, and range. I suppose we should just send out our
> proposal and get everyone's take on it.
>
> Jeff
>
> On Thu, Apr 28, 2016 at 5:06 PM, Dave Abrahams via swift-evolution
> <swift-evolution at swift.org> wrote:
>
> on Thu Apr 28 2016, Jeff Hajewski
> <swift-evolution at swift.org> wrote:
>
> > Thanks for bringing this back into the spotlight Pyry. A few of us have
> been
> > working on this issue here:
> >
> > https://github.com/lorenzoracca/Swift-binary-search
> >
> > However we have sort of stalled as we have been unable to come up with a
> unary
> > approach that Dave suggested using just Bool return values. And of course,
> as
> > you say, the three case order enum would make this a trivial problem.
> >
> > I guess the question is, do we move forward without a unary implementation
> and
> > update if/when we get a three case Order enum or do we wait on a three
> case
> > Order enum and implement a fully generic version once?
>
> Or you could just do it like this (Swift 2.2-compatible). Am I missing
> something?
>
> extension CollectionType {
> /// Returns the index of the first element satisfying `predicate`,
> /// or `endIndex` if no such element exists.
> ///
> /// - Requires: `self` is partitioned with respect to `predicate`;
> /// that is, there exists an index `i` in `startIndex...endIndex`
> /// such that `predicate` returns `false` for every element of
> /// `self[startIndex..<i]` and returns `true` for every element
> /// of `self[i..<endIndex]`.
> @warn_unused_result
> public func binarySearch(
> predicate: (Self.Generator.Element)->Bool
> ) -> Index {
> var len = count
> var min = startIndex
> while len > 0 {
> let half = len/2
> let middle = min.advancedBy(half)
>
> if !predicate(self[middle]) {
> min = middle.successor()
> len -= half.successor()
> } else {
> len = half
> }
> }
> return min
> }
> }
>
> extension CollectionType where Generator.Element : Comparable {
> /// Returns the index of the first element greater than or equal to
> /// `target`, or `endIndex` if no such element exists.
> ///
> /// - Requires: `self` is sorted.
> @warn_unused_result
> public func lowerBound(target: Self.Generator.Element) -> Index {
> return binarySearch { $0 >= target }
> }
>
> /// Returns the index of the first element greater than
> /// `target`, or `endIndex` if no such element exists.
> ///
> /// - Requires: `self` is sorted.
> @warn_unused_result
> public func upperBound(target: Self.Generator.Element) -> Index {
> return binarySearch { $0 > target }
> }
> }
>
> //===--- TEST IT -
> ---------------------------------------------------------===//
> import Darwin
> for _ in 0..<1000 {
> // build a sorted array of up to 30 values in the range 0..<10
> var a : Array<Int> = []
> for _ in 0..<arc4random_uniform(30) {
> a.append(Int(arc4random_uniform(10)))
> }
> a.sortInPlace()
>
> print(a)
>
> for i in -3...14 {
> let l = a.lowerBound(i)
> let u = a.upperBound(i)
> assert(l >= 0)
> assert(u <= a.count)
> assert(l <= u)
> if l > 0 {
> assert(a[l - 1] < i)
> }
> if l < a.count {
> assert(a[l] >= i)
> }
> if u > 0 {
> assert(a[u - 1] <= i)
> }
> if u < a.count {
> assert(a[u] > i)
> }
> }
> }
>
> --
> Dave
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
--
Dave
More information about the swift-evolution
mailing list