Перечислять и архивировать в Coffeescript? - PullRequest
31 голосов
/ 11 апреля 2011

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

Вот шаблоны, которые меня не волнуют:

# 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 ...

Ответы [ 6 ]

29 голосов
/ 11 апреля 2011

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

a = ['a','b','c']
for el,i in a
    alert "Element #{el} is at index #{i}"
13 голосов
/ 11 апреля 2011

Перечисление:

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

zip / zipWith (я узнал об этом у Хаскелла; я предполагаю, что в 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

8 голосов
/ 11 апреля 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, а не мин; поэтому, если вы не хотите обрабатывать значения undefined, сначала вам нужно усечь более длинный массив.

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

5 голосов
/ 18 ноября 2012

В CoffeeScript Cookbook приведена хорошая реализация функции 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

2 голосов
/ 11 апреля 2011

Не забывайте, что 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 в какой-то будущей версии языка.

0 голосов
/ 24 марта 2016

Для почтового индекса, попробуйте это:

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

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

...