+1 on this.

I see a lot of code like this:

sequence.filter(predicate).first

Which is of course is inefficient. However, the go-to optimisation:

sequence.lazy.filter(predicate).first

Is not necessarily better, and has some strange behaviour:

let array = [1, 2, 3, 4, 5, 6]
func noisyPredicate(n: Int) -> Bool {
  print(n, terminator: " ")
  return n > 2
}

array.lazy.filter(noisyPredicate).first
// 1 2 3 1 2 3

AnySequence(array).lazy.filter(noisyPredicate).first
// 1 2 3 4 5 6

If it’s called on a collection, the collection is only evaluated up until the 
element being looked for, but it’s done twice. If it’s called on a sequence, 
the whole sequence is evaluated, regardless of where the element is found.

I think that find is maybe not the best name, though. It’s not immediately 
clear that it doesn’t return an index. I’d prefer to call it first, as in:

extension SequenceType {
  /// Returns the first element where `predicate` returns `true`, or `nil`
  /// if such value is not found.
  public func first(@noescape thatSatisfies: (Self.Generator.Element) throws -> 
Bool) rethrows -> Self.Generator.Element? {
    for elt in self {
      if try thatSatisfies(elt) {
        return elt
      }
    }
    return nil
  }
}

[1, 2, 3, 4, 5].first(thatSatisfies: (Int) throws -> Bool)

[1, 2, 3, 4, 5].first { $0 > 3 }

> On 30 Dec 2015, at 10:13, James Campbell via swift-evolution 
> <[email protected]> wrote:
> 
> We should add the full collection of ruby methods 
> http://matthewcarriere.com/06/23/using-select-reject-collect-inject-and-detect/
>  
> <http://matthewcarriere.com/06/23/using-select-reject-collect-inject-and-detect/>
> 
> 
> 
> Sent from my iPhone
> 
> On 30 Dec 2015, at 02:40, Keith Smiley via swift-evolution 
> <[email protected] <mailto:[email protected]>> wrote:
> 
>> +1. We've added an extension for this and find it very useful.
>> On Tue, Dec 29, 2015 at 18:38 Kevin Ballard via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> I'm proposing a new extension method on SequenceType called find(). It's 
>> similar to CollectionType.indexOf() except it returns the element:
>>  
>> extension SequenceType {
>>     /// Returns the first element where `predicate` returns `true`, or `nil`
>>     /// if such value is not found.
>>     public func find(@noescape predicate: (Self.Generator.Element) throws -> 
>> Bool) rethrows -> Self.Generator.Element? {
>>         for elt in self {
>>             if try predicate(elt) {
>>                 return elt
>>             }
>>         }
>>         return nil
>>     }
>> }
>>  
>> -Kevin Ballard
>>  
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>  _______________________________________________
> swift-evolution mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to