2013-09-22 10 views
7

Ich würde gerne die idiomatische Art, mit der Sie über Sammlungen unterschiedlicher Größe in clojure arbeiten. Gibt es eine Möglichkeit, der Funktion 'map' zu sagen, den Rest einer Sammlung mit einem Standardwert zu füllen?Verwenden von 'Karte' mit verschiedenen Größen in clojure

Als Beispiel nehme ich habe 3 Vektoren:

(def x [1 2 3 4]) 
(def y [1 2 3 4 5]) 
(def z [1 2 3 4 5 6 7]) 

(map + x y z) ; yields (3 6 9 12) 

In diesem Fall ist, wie kann ich pad x und y mit Nullen und diese Ausbeute haben:

(3 6 9 12 10 6 7) 

Antwort

10

map nicht tun Sie es selbst, aber Sie können eine Kombination von concat und repeat verwenden, um das gewünschte Ergebnis zu erhalten:

(def x [1 2 3 4]) 
(def y [1 2 3 4 5]) 
(def z [1 2 3 4 5 6 7]) 

(map + 
    (concat x (repeat 0)) 
    (concat y (repeat 0)) 
    z) ; => (3 6 9 12 10 6 7) 

Hier finden Sie die API-Dokumentation für concat und für repeat.

Und hier ist eine Skizze, wie Sie dies etwas abstrahieren können, so dass Sie nicht wissen müssen, welche der Sammlungen am längsten ist. (Wenn Sie im obigen Codefragment concat alle Sammlungen zu (repeat 0) haben, haben Sie eine unendliche Sequenz).

(defn map-longest 
    [f default & colls] 
    (lazy-seq 
    (when (some seq colls) 
    (cons 
     (apply f (map #(if (seq %) (first %) default) colls)) 
     (apply map-longest f default (map rest colls)))))) 

(map-longest + 
      0 
      [1 2 3 4] 
      [1 2 3 4 5] 
      [1 2 3 4 5 6 7]) ; => (3 6 9 12 10 6 7) 

Sie können ein paar andere Ansätze als Antworten auf this previous question on Stack Overflow sehen.