2010-11-16 8 views
20

In Python kann ich dies tun:Aufzählen über eine Sequenz in Clojure?

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

Welche Ausgänge:

0 dog 
1 cat 
2 bird 

Wie würde ich die gleiche Sache in Clojure erreichen? Ich überlegte, ein Listenverständnis wie folgt zu verwenden:

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

Aber das druckt jede Kombination von Zahl und Tier aus. Ich schätze, es gibt eine einfache und elegante Möglichkeit, dies zu tun, aber ich sehe es nicht.

Antwort

33

Es gibt map-indexed in Kern als 1,2.

Ihr Beispiel wäre:

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

Schnell Lösung:

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

Oder, wenn Sie wollen, dass es in einer Funktion wickeln:

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

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

Was hier passiert, ist der Funktionsvektor zu jedem Elemente in beiden Sequenzen angewandt wird, und Das Ergebnis wird in einer faulen Sammlung gesammelt.

Probieren Sie es in Ihrer Replik.

9

Verwendung von clojure.contrib.seq indiziert:

Verbrauch: (indexed s) Gibt eine faule Folge von [index, item] Paaren, wobei Artikel von 's' kommen und Indizes zählen von Null auf.

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

Für Ihr Beispiel ist dies

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

heh. Werfen Sie einen Blick auf den Quellcode für die Funktion indiziert: https://github.com/clojure/clojure-contrib/blob/b8d2743d3a89e13fc9deb2844ca2167b34aaa9b6/src/main/clojure/clojure/contrib/seq.clj#L51 – Leonel

+0

heh. Ich kenne. Ich frage mich, warum Sie in Ihrem Beispiel die Funktion 'enum' benannt haben :-) – ordnungswidrig

4

map-indexed sieht richtig, aber: Sie wirklich in den anderen Antworten args Sachen müssen alle von der doseq und dekonstruieren wir?

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

EDIT: wie @gits bemerkt dies in der REPL funktioniert aber nicht respektiert, dass clojure standardmäßig faul ist. dorun scheint dafür am nächsten among doseq, doall and doseq zu sein. doseq, wie auch immer, scheint der idiomatische Favorit hier zu sein. die Paare, die Elemente eines Vektors mit ihren Indizes

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

'map-indexed' gibt einen Lazy Seq zurück. 'doseq' ist notwendig, um zu gewährleisten, dass Nebenwirkungen jetzt und nicht später auftreten (in diesem Fall erfolgt der Ausdruck durch' println'). – glts

+0

@git richtig und danke, ich habe das bemerkt, aber nicht aktualisiert, weil ich immer noch lerne und nicht weiß, ob doseq hier wirklich beliebt ist. –

1

Eine weitere Option ist reduce-kv, zu verwenden.

So

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

oder vielleicht etwas deutlicher

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

ich diese Lösung hier nicht über einen mit doseq holen würde, aber es ist gut bekannt, diese Spezialisierung zu sein für Vektoren in reduce-kv.