Ответ 1
В ядре находится map-indexed
с 1.2.
Ваш пример:
(doseq [[i animal] (map-indexed vector ["dog" "cat" "bird"])]
(println i animal))
В Python я могу это сделать:
animals = ['dog', 'cat', 'bird']
for i, animal in enumerate(animals):
print i, animal
Какие выходы:
0 dog
1 cat
2 bird
Как бы выполнить то же самое в Clojure? Я рассмотрел использование такого списка:
(println
(let [animals ["dog" "cat" "bird"]]
(for [i (range (count animals))
animal animals]
(format "%d %d\n" i animal))))
Но это печатает каждую комбинацию числа и животных. Я предполагаю, что есть простой и элегантный способ сделать это, но я не вижу его.
В ядре находится map-indexed
с 1.2.
Ваш пример:
(doseq [[i animal] (map-indexed vector ["dog" "cat" "bird"])]
(println i animal))
Использовать индексированный из clojure.contrib.seq:
Использование: (indexed s)
Возвращает ленивую последовательность пар [index, item], где появляются элементы
из 's' и индексы подсчитываются с нуля.
(indexed '(a b c d)) => ([0 a] [1 b] [2 c] [3 d]
Для вашего примера это
(require 'clojure.contrib.seq)
(doseq [[i animal] (clojure.contrib.seq/indexed ["dog", "cat", "bird"])]
(println i animal))
Быстрое решение:
(let [animals ["dog", "cat", "bird"]]
(map vector (range) animals))
Или, если вы хотите обернуть его в функцию:
(defn enum [s]
(map vector (range) s))
(doseq [[i animal] (enum ["dog", "cat", "bird"])]
(println i animal))
Что здесь происходит, так это вектор функции применяется к каждому элементу в обеих последовательностях, и результат собирается в ленивой коллекции.
Вперед, попробуйте в своем repl.
map-indexed
выглядит правильно, но: действительно ли нам нужны все doseq
и деконструкция материалов args в других ответах?
(map-indexed println ["dog", "cat", "bird"])
EDIT:
как отмечено @gits, это работает в REPL, но не считает, что по умолчанию clojure является ленивым. dorun
кажется наиболее близким среди doseq
, doall
и doseq
для этого. doseq
, как бы там ни было, кажется, здесь идиоматический фаворит.
(dorun (map-indexed println ["dog", "cat", "bird"]))
Еще один вариант - использовать reduce-kv
, который связывает элементы вектора с их индексами.
Таким образом,
(reduce-kv #(println %2 %3) nil ["dog" "cat" "bird"])
или, возможно, немного более явный
(reduce-kv (fn [_ i animal] (println i animal)) nil ["dog" "cat" "bird"])
Я бы не выбрал это решение по сравнению с doseq
здесь, но хорошо знать эту специализацию для векторов в reduce-kv
.