перечислить и заархивировать в Coffeescript?

Исходя из Python, мне нравятся многие функции, которые Coffeescript заимствует из Python и Perl (диапазоны/срезы, включения, присваивания деструктурирования). Есть ли в Coffeescript синтаксический сахар для имитации функций Python enumerate или zip (itertools.izip)?

Вот шаблоны, которые мне не очень интересны:

# an enumerate call would be helpful here
i = 0
for x in arr
  ... use x and i ...
  i++

а также

# a zip would be useful here
n = Math.min(arr1.length,arr2.length)
for i in 0...n
  x = arr1[i]; y = arr2[i]
  ... use x and y ...

person yonran    schedule 11.04.2011    source источник


Ответы (6)


forEach эффективно встроен:

a = ['a','b','c']
for el,i in a
    alert "Element #{el} is at index #{i}"
person Mark Smith    schedule 11.04.2011
comment
Спасибо. Кажется, я знал это когда-то, но это было так просто, что я забыл. - person yonran; 11.04.2011
comment
Я действительно проверил справочник по языку, прежде чем написать свой ответ, но, похоже, это не задокументировано или что-то еще скорее всего не нашел. - person Jörg W Mittag; 11.04.2011
comment
Это последний ответ в FAQ, но я не думаю, что есть явный пример в другом месте. - person Mark Smith; 11.04.2011
comment
Я нашел это случайно, играя с синтаксисом. Затем я проверил веб-сайт, но ничего не нашел об этом и начал задаваться вопросом, официально ли это признано и поддерживается. - person Shrikant Sharat; 02.05.2011
comment
разве это не должно быть of для итерации объекта? - person Ilia Choly; 08.08.2011
comment
А у вас параметры наоборот. индекс, элемент - person Nick Daniels; 07.11.2011

Перечислить:

arr.forEach (x, i) ->
    ... use x and i ...

zip / zipWith (я узнал об этом от Haskell; я предполагаю, что они означают одно и то же в Python?):

zip = (arr1, arr2) ->
  basic_zip = (el1, el2) -> [el1, el2]
  zipWith basic_zip, arr1, arr2

zipWith = (func, arr1, arr2) ->
  min = Math.min arr1.length, arr2.length
  ret = []

  for i in [0...min]
    ret.push func(arr1[i], arr2[i])

  ret

Некоторые примеры (проверено):

zip([1, 2, 3], [4, 5, 6])          # => [[1, 4], [2, 5], [3, 6]]

add = (el1, el2) -> el1 + el2
zipWith(add, [1, 2, 3], [4, 5, 6]) # => [5, 7, 9]

Обновление: новая реализация в стиле Haskell, просто для развлечения. Не так круто без сопоставления с образцом, ну да ладно..

zipWith = (func, arr1, arr2) ->
  return [] if arr1.length is 0 or arr2.length is 0

  el1 = arr1.shift()
  el2 = arr2.shift()

  ret_arr = zipWith func, arr1, arr2
  ret_arr.unshift func(el1, el2)

  ret_arr

О, чувак, это было весело. ТАК нужно больше таких вопросов: D

Суть для zip и zipWith

person Jon Gauthier    schedule 11.04.2011
comment
Спасибо за реализации zipWith. Я буду держать их под рукой для кода node.js. - person yonran; 11.04.2011

Стандартной библиотекой для архивирования и других подобных функций является Underscore.js, и, как оказалось, она была создана Джереми. Ашкенас, человек, стоящий за CoffeeScript. С его помощью вы можете написать свой пример zip как

for elems in _.zip(arr1, arr2)
  x = elems[0]; y = elems[1]
  ...

или еще лучше

for [x, y] in _.zip(arr1, arr2)
  ...

с помощью сопоставления с образцом. Обратите внимание, однако, что _.zip использует max длину arr1 и arr2, а не min; поэтому, если вы не хотите обрабатывать значения undefined, вам следует сначала обрезать более длинный массив.

Существует также реализация Underscore на CoffeeScript, Underscore.coffee, которая является отличным местом для посмотрите, если вам интересно, как реализовать конкретный цикл в CoffeeScript.

person Trevor Burnham    schedule 11.04.2011

В поваренной книге CoffeeScript приведена хорошая реализация функции zip:

# Usage: zip(arr1, arr2, arr3, ...)
zip = () ->
  lengthArray = (arr.length for arr in arguments)
  length = Math.min(lengthArray...)
  for i in [0...length]
    arr[i] for arr in arguments

zip([0, 1, 2, 3], [0, -1, -2, -3])
# => [[0, 0], [1, -1], [2, -2], [3, -3]]

http://coffeescriptcookbook.com/chapters/arrays/zip-function

person polarblau    schedule 18.11.2012

Не забывайте, что CoffeeScript — это просто альтернативный синтаксис для ECMAScript. По крайней мере, для вашего первого примера есть отличная функция ECMAscript (Array.prototype.forEach), который уже делает то, что вы хотите:

arr = ["a", "b", "c"]

arr.forEach (el, i) ->
  alert "Element #{el} is at index #{i}"

К сожалению, нет Array.prototype.zip или Array.prototype.zipWith. Это кажется довольно большим упущением, особенно если учесть, что есть и reduce, и reduceRight, последнего из которых нет во многих других языках. Я предполагаю, что это простая оплошность, и мы увидим zip в какой-то будущей версии языка.

person Jörg W Mittag    schedule 11.04.2011

Для zip попробуйте этот:

zip = (x...) ->
  (y[i] for y in x for i in [0...Math.min (y.length for y in x)...])

Если вы предпочитаете архивировать до конца, используйте Math.max().

person Jess Austin    schedule 24.03.2016