How to implement array.any() and array.all() methods in Coffeescript?
How to implement array.any()
开发者_如何学Goand array.all()
methods in Coffeescript?
Those are actually part of Javascript 1.6 and will work just the same in CoffeeScript. You want some and every.
I don't know what environment you're in, but IE < 9 doesn't seem to support those methods. They're pretty easy to add. There's a snippet of code on those pages that show you compatibility code and if you want you can translate them to CoffeeScript, though you don't have to.
A cruder, simpler way would be (untested):
if not Array.prototype.some
Array.prototype.some = (f) -> (x for x in @ when f(x)).length > 0
if not Array.prototype.every
Array.prototype.every = (f) -> (x for x in @ when f(x)).length == @length
But neither of those have short circuit logic. Edit: But see Ricardo's answer for a better version of them.
Short-circuited (optimized) versions:
Array.prototype.some ?= (f) ->
(return true if f x) for x in @
return false
Array.prototype.every ?= (f) ->
(return false if not f x) for x in @
return true
The ?=
is for "existential assignment", only runs when that property is null
/undefined
.
Check out underscore.js, which provides you with _.any
and _.all
methods (a.k.a. _.some
and _.every
) that will run in any major JS environment. Here's how they're implemented in CoffeeScript in underscore.coffee:
_.some = (obj, iterator, context) ->
iterator ||= _.identity
return obj.some iterator, context if nativeSome and obj.some is nativeSome
result = false
_.each obj, (value, index, list) ->
_.breakLoop() if (result = iterator.call(context, value, index, list))
result
_.every = (obj, iterator, context) ->
iterator ||= _.identity
return obj.every iterator, context if nativeEvery and obj.every is nativeEvery
result = true
_.each obj, (value, index, list) ->
_.breakLoop() unless (result = result and iterator.call(context, value, index, list))
result
(These depend on _.each
, which is a straightforward iteration method, and _.breakLoop
, which just throws an exception.)
I was looking at this today and decided to implement all
as a fold, and I suppose you could do the same for any
as well (but it doesn't short circuit, either):
all = (someArray, predicate) ->
reduceAll = (left, right) ->
return left and right
return [predicate(elem) for elem in someArray].reduce(reduceAll, true)
The non-short-circuiting any
would be mostly similar:
reduceAny = (left, right) ->
return left or right
[p(elem) for elem in someArray].reduce(reduceAny, false)
I did all
this way because I found it to be readable. Also, I just did it as a free-floating function instead of an array method.
精彩评论