2010-11-16 18 views
20

En Python que puedo hacer esto:¿Enumerar una secuencia en Clojure?

animals = ['dog', 'cat', 'bird'] 
for i, animal in enumerate(animals): 
    print i, animal 

que da salida:

0 dog 
1 cat 
2 bird 

¿Cómo puedo lograr lo mismo en Clojure? Consideré usar una lista de comprensión como esta:

(println 
    (let [animals ["dog" "cat" "bird"]] 
    (for [i (range (count animals)) 
      animal animals] 
     (format "%d %d\n" i animal)))) 

Pero esto imprime cada combinación de número y animal. Supongo que hay una manera simple y elegante de hacer esto, pero no lo estoy viendo.

Respuesta

33

Hay map-indexed en el núcleo como de 1,2.

Su ejemplo sería:

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

solución rápida:

(let [animals ["dog", "cat", "bird"]] 
    (map vector (range) animals)) 

O, si se quiere envolver en una función:

(defn enum [s] 
    (map vector (range) s)) 

(doseq [[i animal] (enum ["dog", "cat", "bird"])] 
    (println i animal)) 

Lo que sucede aquí es el vector de función se aplica a cada elemento en ambas secuencias, y el resultado se recoge en una colección floja.

Adelante, pruébalo en tu respuesta.

9

Uso indexada desde clojure.contrib.seq:

Uso: (indexed s) devuelve una secuencia lenta de [índice, elemento] pares, donde los artículos vienen de 's' y los índices contar a partir de cero.

(indexed '(a b c d)) => ([0 a] [1 b] [2 c] [3 d]

Para su ejemplo, esto es

(require 'clojure.contrib.seq) 
(doseq [[i animal] (clojure.contrib.seq/indexed ["dog", "cat", "bird"])] 
    (println i animal)) 
+0

heh. Eche un vistazo al código fuente de la función indexada: https://github.com/clojure/clojure-contrib/blob/b8d2743d3a89e13fc9deb2844ca2167b34aaa9b6/src/main/clojure/clojure/contrib/seq.clj#L51 – Leonel

+0

heh. Lo sé. Me pregunto por qué nombraste la función 'enum' en tu ejemplo, luego :-) – ordnungswidrig

4

map-indexed se ve bien, pero: ¿Necesitamos realmente todas las cosas doseq y deconstrucción de argumentos en las otras respuestas?

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

EDIT: como señaló @gits esto funciona en el REPL pero no respeta que clojure es perezoso por defecto. dorun parece ser el más cercano among doseq, doall and doseq para esto. doseq, howver, parece ser el favorito idiomático aquí.

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

'map-indexed' devuelve un seq perezoso. 'doseq' es necesario para garantizar que los efectos secundarios ocurran ahora, no después (en este caso, la impresión efectuada por' println'). – glts

+0

@git right y gracias, lo noté pero no actualicé porque todavía estoy aprendiendo y no sé si doseq es el idioma favorito aquí. –

1

Sin embargo, otra opción es utilizar reduce-kv, que los pares de los elementos de un vector con sus índices.

Por lo tanto,

(reduce-kv #(println %2 %3) nil ["dog" "cat" "bird"]) 

o quizás un poco más explícita la

(reduce-kv (fn [_ i animal] (println i animal)) nil ["dog" "cat" "bird"]) 

yo no volvería a escoger esta solución sobre el que tiene doseq aquí, pero es bueno estar al tanto de esta especialización para vectores en reduce-kv.

Cuestiones relacionadas