Reputation: 36098
I'm putting together some common functions I use in my app and came up with the below extensions:
public extension CollectionType {
public func toArray() -> [Self.Generator.Element] {
return self.map { $0 }
}
}
public extension Array {
public func any(fn: (Element) -> Bool) -> Bool {
return self.filter(fn).count > 0
}
public func all(fn: (Element) -> Bool) -> Bool {
return self.filter(fn).count == self.count
}
public func take(count:Int) -> [Element] {
var to = [Element]()
var i = 0
while i < self.count && i < count {
to.append(self[i++])
}
return to
}
public func skip(count:Int) -> [Element] {
var to = [Element]()
var i = count
while i < self.count {
to.append(self[i++])
}
return to
}
}
Can they be applied to a lower level type like SequenceType
? Also, do I have to put @noescape
anywhere in these functions?
Upvotes: 1
Views: 1469
Reputation: 41226
Generally speaking, @noescape
should be used anytime the closure isn't saved for later usage, it seems appropriate for both of the closures you have here.
It's not really clear what you mean by "can they be applied to a lower level type" More or less obviously, you could create versions of these extensions for some of the other protocols, but your existing skip
function can only be applied to Array
(btw, there's an existing function dropFirst
on SequenceType
that does exactly the same thing)
For both take
and skip
you might want to actually consider returning an ArraySlice
as this avoids copying the original array:
extension Array {
func take(count:Int) -> ArraySlice<Element> {
return self[0..<count]
}
func drop(count:Int) -> ArraySlice<Element> {
return self[count..<self.count]
}
}
Note that for both of these, you probably (may) want to add some error detection/handling as they'll blow up if count > self.count
.
Likewise, using contains
to implement any
and all
is probably more efficient since it doesn't result in building a new array just for the count:
extension Array {
func any(@noescape predicate:(Element)->Bool) -> Bool {
return contains(predicate)
}
func all(@noescape predicate:(Element)->Bool) -> Bool {
return !contains { !predicate($0) }
}
}
As an example of defining some of these as extensions to SequenceType
:
extension SequenceType {
func any(@noescape predicate:(Generator.Element)->Bool) -> Bool {
return contains(predicate)
}
func all(@noescape predicate:(Generator.Element)->Bool) -> Bool {
return !contains { !predicate($0) }
}
func drop(count:Int) -> Self.SubSequence {
return self.dropFirst(count)
}
}
And, as an example of implementing take
as a Sequence extension:
struct TakeFromSequenceSequence<S:SequenceType> : SequenceType {
var limit : Int
var sequence : S
func generate() -> AnyGenerator<S.Generator.Element> {
var generator = sequence.generate()
var limit = self.limit
return anyGenerator {
guard limit > 0 else {
return nil
}
limit = limit - 1
return generator.next()
}
}
}
extension SequenceType {
func take(count:Int) -> TakeFromSequenceSequence<Self> {
return TakeFromSequenceSequence(limit: count, sequence: self)
}
}
Upvotes: 3