Перечислить последовательность в Clojure? - PullRequest
21 голосов
/ 16 ноября 2010

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

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

Ответы [ 5 ]

35 голосов
/ 16 ноября 2010

По состоянию на 1.2. map-indexed в ядре.

Ваш пример будет:

(doseq [[i animal] (map-indexed vector ["dog" "cat" "bird"])]
  (println i animal))
8 голосов
/ 16 ноября 2010

Использовать индексируется с 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))
8 голосов
/ 16 ноября 2010

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

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

Здесь происходит то, что вектор функции применяется к каждому элементу в обеих последовательностях, а результат собирается в ленивый набор.

Давай, попробуй в своем репле.

4 голосов
/ 10 марта 2016

map-indexed выглядит правильно, но: нам действительно нужны все вещи doseq и деконструкции аргументов в других ответах?

(map-indexed println ["dog", "cat", "bird"])

EDIT: как отмечает @gits, это работает в REPL, но не учитывает, что clojure по умолчанию ленив. dorun кажется самым близким среди doseq, doall и doseq для этого. doseq, однако, кажется здесь идиоматическим фаворитом.

(dorun (map-indexed println ["dog", "cat", "bird"]))
1 голос
/ 13 марта 2016

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

...