[swift-evolution] Proposal: Add scan, takeWhile, dropWhile, and iterate to the stdlib

Susan Cheng susan.doggie at gmail.com
Tue Dec 29 08:10:23 CST 2015


Consider this:

extension CollectionType where Generator.Element : Equatable {

    /// Returns a subsequence, until a element equal to `value`, containing
the
    /// initial elements.
    ///
    /// If none of elements equal to `value`, the result contains all
    /// the elements of `self`.
    ///
    /// - Complexity: O(`self.count`)
    @warn_unused_result
    public func prefixUntil(element: Self.Generator.Element) ->
Self.SubSequence {
        return self.prefixUpTo(self.indexOf(element) ?? self.endIndex)
    }
}


extension CollectionType {

    /// Returns a subsequence, until a element satisfying the predicate,
containing the
    /// initial elements.
    ///
    /// If none of elements satisfying the predicate, the result contains
all
    /// the elements of `self`.
    ///
    /// - Complexity: O(`self.count`)
    @warn_unused_result
    public func prefixUntil(@noescape predicate: (Self.Generator.Element)
throws -> Bool) rethrows -> Self.SubSequence {
        return self.prefixUpTo(try self.indexOf(predicate) ?? self.endIndex)
    }
}


extension CollectionType where Generator.Element : Equatable, Index :
BidirectionalIndexType {
    /// Returns a subsequence, until a element equal to `value`, containing
the
    /// final elements of `self`.
    ///
    /// If none of elements equal to `value`, the result contains all
    /// the elements of `self`.
    ///
    /// - Complexity: O(`self.count`)
    @warn_unused_result
    public func suffixUntil(element: Self.Generator.Element) ->
Self.SubSequence {
        return self.suffixFrom(self.reverse().indexOf(element)?.base ??
self.startIndex)
    }
}


extension CollectionType where Index : BidirectionalIndexType {
    /// Returns a subsequence, until a element satisfying the predicate,
containing the
    /// final elements of `self`.
    ///
    /// If none of elements satisfying the predicate, the result contains
all
    /// the elements of `self`.
    ///
    /// - Complexity: O(`self.count`)
    @warn_unused_result
    public func suffixUntil(@noescape predicate: (Self.Generator.Element)
throws -> Bool) rethrows -> Self.SubSequence {
        return self.suffixFrom(try self.reverse().indexOf(predicate)?.base
?? self.startIndex)
    }
}

and here are my
utilities:https://github.com/SusanDoggie/Doggie/blob/master/Doggie/Foundation.swift


Kevin Ballard <kevin at sb.org> 於 2015年12月29日 上午7:59 寫道:

## Introduction

Add a few more functional sequence utilities to the standard library.

## Motivation

We have map, filter, and reduce, but we're missing a bunch of useful
utilities like scan, iterate, takeWhile, and dropWhile. Interestingly, the
stdlib includes an implementation of scan in the doc comment for
LazySequenceType, it just doesn't actually provide it as API.

## Proposed solution

We extend SequenceType with 3 new methods scan, takeWhile, and dropWhile.
We also add a single global function iterate.

## Detailed design

We add the following extension to SequenceType:

extension SequenceType {
   func scan<T>(initial: T, @noescape combine: (T, Self.Generator.Element)
throws -> T) rethrows -> [T]
   func dropWhile(@noescape dropElement: (Self.Generator.Element) throws ->
Bool) rethrows -> [Self.Generator.Element]
   func takeWhile(@noescape takeElement: (Self.Generator.Element) throws ->
Bool) rethrows -> [Self.Generator.Element]
}

These all take functions, so to follow convention they're @noescape and
return arrays. We also provide an extension of CollectionType that
overrides a couple of these methods:

extension CollectionType {
   func dropWhile(@noescape dropElement: (Self.Generator.Element) throws ->
Bool) rethrows -> Self.SubSequence
   func takeWhile(@noescape takeElement: (Self.Generator.Element) throws ->
Bool) rethrows -> Self.SubSequence
}

We also provide lazy versions:

extension LazySequenceType {
   func scan<T>(initial: T, combine: (T, Self.Generator.Element) -> T) ->
LazyScanSequence<Self.Elements, T>
   func dropWhile(dropElement: (Self.Generator.Element) -> Bool) ->
LazyDropWhileSequence<Self.Elements>
   func takeWhile(takeElement: (Self.Generator.Element) -> Bool) ->
LazyTakeWhileSequence<Self.Elements>
}

extension LazyCollectionType {
   func dropWhile(dropElement: (Self.Generator.Element) -> Bool) ->
LazyDropWhileCollection<Self.Elements>
   func takeWhile(takeElement: (Self.Generator.Element) -> Bool) ->
LazyTakeWhileCollection<Self.Elements>
}

No collection variant of scan is provided because that would require
storing the last value in the index itself, which would cause problems if
the combine function isn't pure.

LazyDropWhileCollection would behave similarly to LazyFilterCollection in
that it runs the predicate against the elements to drop when accessing
startIndex; unlike LazyFilterCollection, because there's nothing else to
skip after that point, the index itself can actually be Self.Elements.Index
(just like a slice). LazyTakeWhileCollection also runs the predicate
against the first element when accessing startIndex, but it does need a
unique index type (because endIndex has to be some sentinel value, as it
doesn't know where the end is until you reach that point; this index type
would therefore only conform to ForwardIndexType).

And finally, we provide a global function

func iterate<T>(initial: T, _ f: T -> T) -> IterateSequence<T>

This function is inherently lazy and yields an infinite list of nested
applications of the function, so iterate(x, f) yields a sequence like [x,
f(x), f(f(x)), ...].

-Kevin Ballard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151229/0ac2c88d/attachment.html>


More information about the swift-evolution mailing list