Ответ 1
forEach эффективно встроен:
a = ['a','b','c']
for el,i in a
alert "Element #{el} is at index #{i}"
Начиная с 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 ...
forEach эффективно встроен:
a = ['a','b','c']
for el,i in a
alert "Element #{el} is at index #{i}"
Перечислите:
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
О, мужик, это было весело. SO требует больше вопросов, таких как: D
Для zip и других подобных служебных функций Underscore.js - это в значительной степени стандартная библиотека, и это, вероятно, было создано Джереми Ашкенасом, человеком, стоящим за CoffeeScript, С его помощью вы можете написать свой пример zip как
for elems in _.zip(arr1, arr2)
x = elems[0]; y = elems[1]
...
или еще лучше
for [x, y] in _.zip(arr1, arr2)
...
используя сопоставление с образцом. Обратите внимание, однако, что _.zip
использует максимальную длину arr1
и arr2
, а не min; поэтому, если вы не хотите обрабатывать значения undefined
, вы должны сначала обрезать более длинный массив.
Там также реализована программа CoffeeScript Underscore, Underscore.coffee, и это отличное место для просмотра, если вам интересно, как реализовать определенный цикл в CoffeeScript.
Cookbook 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
Не забывайте, что 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
в некоторой будущей версии языка.
Для zip попробуйте следующее:
zip = (x...) ->
(y[i] for y in x for i in [0...Math.min (y.length for y in x)...])
Если вы предпочитаете застегивать весь путь до конца, используйте Math.max()
.