Как реализовать методы array.any() и array.all() в Coffeescript?

Как реализовать методы array.any() и array.all() в Coffeescript?

Ответ 1

На самом деле это часть Javascript 1.6 и будет одинаково работать в CoffeeScript. Вы хотите some и every.

Я не знаю, в какой среде вы находитесь, но IE < 9, похоже, не поддерживает эти методы. Их довольно легко добавить. Там фрагмент кода на тех страницах, которые показывают код совместимости, и если вы хотите, вы можете перевести их на CoffeeScript, хотя вы не должны.

Более грубый, более простой способ был бы (непроверен):

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

Но ни один из них не имеет логики короткого замыкания. Изменить. Но см. ответ Рикардо для лучшей версии.

Ответ 2

Короткозамкнутые (оптимизированные) версии:

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

?= предназначен для "экзистенциального назначения", выполняется только тогда, когда это свойство null/undefined.

Ответ 3

Отметьте underscore.js, который предоставляет вам методы _.any и _.all (aka _.some и _.every) который будет работать в любой крупной среде JS. Вот как они реализованы в CoffeeScript в 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

(Они зависят от _.each, который представляет собой простой метод итерации, и _.breakLoop, который просто генерирует исключение.)

Ответ 4

Я смотрел на это сегодня и решил реализовать all как сгиб, и я полагаю, что вы могли бы сделать то же самое и для any (но это тоже не короткое замыкание):

all = (someArray, predicate) ->
  reduceAll = (left, right) ->
    return left and right
  return [predicate(elem) for elem in someArray].reduce(reduceAll, true)

Некороткое замыкание any будет в основном аналогичным:

reduceAny = (left, right) ->
    return left or right
[p(elem) for elem in someArray].reduce(reduceAny, false)

Я сделал all таким образом, потому что нашел его читаемым. Кроме того, я просто сделал это как функцию свободного плавания вместо метода массива.