开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜