Подтвердить что ты не робот

Перечислить последовательность в Clojure?

В 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))))

Но это печатает каждую комбинацию числа и животных. Я предполагаю, что есть простой и элегантный способ сделать это, но я не вижу его.

4b9b3361

Ответ 1

В ядре находится map-indexed с 1.2.

Ваш пример:

(doseq [[i animal] (map-indexed vector ["dog" "cat" "bird"])]
  (println i animal))

Ответ 2

Использовать индексированный из 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))

Ответ 3

Быстрое решение:

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

Ответ 4

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"]))

Ответ 5

Еще один вариант - использовать 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.