Gibt es ein Äquivalent für die Zip-Funktion in Clojure Core oder Contrib?


130

In Clojure möchte ich zwei Listen kombinieren, um eine Liste von Paaren zu erhalten.

> (zip '(1 2 3) '(4 5 6))  
((1 4) (2 5) (3 6))

In Haskell oder Ruby heißt die Funktion zip . Die Implementierung ist nicht schwierig, aber ich wollte sicherstellen, dass mir keine Funktion in Core oder Contrib entgeht.

Es ist ein Zip - Namespace in Kern, aber es wird beschrieben , wie der Zugang zum Zipper funktionalen Technik, die scheint nicht zu sein , was ich bin nach.

Gibt es eine äquivalente Funktion zum Kombinieren von zwei oder mehr Listen auf diese Weise in Core?

Wenn dies nicht der Fall ist, liegt es daran, dass es einen idiomatischen Ansatz gibt, der die Funktion unnötig macht?


Es gibt eine zipFunktion in der Tupelo-Bibliothek: cloojure.github.io/doc/tupelo/tupelo.core.html#var-zip
Alan Thompson

Antworten:


220
(map vector '(1 2 3) '(4 5 6))

macht was du willst:

=> ([1 4] [2 5] [3 6])

Haskell braucht eine Sammlung von zipWith( zipWith3, zipWith4, ...) Funktionen, weil sie alle der Notwendigkeit einer spezifisch sein Typ ; Insbesondere muss die Anzahl der von ihnen akzeptierten Eingabelisten festgelegt werden. (Die zip, zip2, zip3, ... Familie kann als Spezialisierung der angesehen werden zipWithFamilie zur gemeinsamen Nutzung Fall fache Vervielfachung).

Im Gegensatz dazu unterstützen Clojure und andere Lisps Funktionen mit variabler Arität gut. mapist einer von ihnen und kann auf ähnliche Weise wie bei Haskell zum "Tupeln" verwendet werden

zipWith (\x y -> (x, y))

Die idiomatische Methode zum Erstellen eines "Tupels" in Clojure besteht darin, einen kurzen Vektor zu erstellen, wie oben dargestellt.

(Der Vollständigkeit halber ist zu beachten, dass Haskell mit einigen grundlegenden Erweiterungen variable Aritätsfunktionen zulässt. Die Verwendung dieser Funktionen erfordert jedoch ein gutes Sprachverständnis, und die Vanille Haskell 98 unterstützt sie wahrscheinlich überhaupt nicht. Daher sind feste Aritätsfunktionen vorzuziehen für die Standardbibliothek.)


8
Beachten Sie, dass sich dies anders verhält als zipwenn die Sammlungen nicht dieselbe Länge haben. Ruby setzt die Verarbeitung fort und liefert nils für die kürzere Sammlung, während Clojure die Verarbeitung beendet, sobald eine der Sammlungen erschöpft ist.
Nate W.

@NateW. Das ist gut zu bemerken, danke. In Haskell zipverhält es sich mapin dieser Hinsicht wie Clojure .
Michał Marczyk

1
Darf ich um eine Referenz zu Haskell-Funktionen mit variabler Arität bitten?
Teodor

22
(partition 2 (interleave '(1 2 3) '(4 5 6))) 
=> ((1 4) (2 5) (3 6))

oder allgemeiner

(defn zip [& colls]
  (partition (count colls) (apply interleave colls)))

(zip '( 1 2 3) '(4 5 6))           ;=> ((1 4) (2 5) (3 6))

(zip '( 1 2 3) '(4 5 6) '(2 4 8))  ;=> ((1 4 2) (2 5 4) (3 6 8))


11

Um Ihnen genau das zu geben, was Sie wollten, erhalten Sie durch Zuordnen listzwischen den beiden Listen eine Liste mit Listen wie in Ihrem Beispiel. Ich denke, dass viele Clojurianer dazu neigen würden, Vektoren dafür zu verwenden, obwohl es mit allem funktionieren wird. und die Eingänge müssen nicht vom gleichen Typ sein. map erstellt daraus seqs und ordnet dann die seqs zu, sodass jede seq'able-Eingabe einwandfrei funktioniert.

(map list '(1 2 3) '(4 5 6))
(map list  [1 2 3] '(4 5 6))
(map hash-map  '(1 2 3) '(4 5 6))
(map hash-set  '(1 2 3) '(4 5 6))

1
Ich denke du meinst Hash-Map und Hash-Set anstelle von Map und Set.
Cgrand

3

Der eingebaute Weg wäre einfach die Funktion 'Interleave':

(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]

6
Um das Ziel des OP zu erreichen, sollten Sie hinzufügen(partition 2 (interleave [1 2 3 4][5 6 7 8]))
Skuro

Ja - Anscheinend habe ich mir die gewünschte Ausgabe des OP nicht zu genau angesehen.
lsh

-1

Es gibt eine Funktion namens zipmap, die einen ähnlichen Effekt haben kann (zipmap (1 2 3)(4 5 6)). Die Ausgabe lautet wie folgt: {3 6, 2 5, 1 4}


zipmap gibt Ihnen eine Karte zurück, die die Bestellung nicht garantiert
Ilya Shinkarenko

-2

# (Kartenliste% anwenden) transponiert eine Matrix genau wie die Python zip * -Funktion. Als Makrodefinition:

user => (defmacro py-zip [lst] `(Kartenliste anwenden ~ lst))

# 'user / py-zip

Benutzer => (py-zip '((1 2 3 4) (9 9 9 9) (5 6 7 8)))

((1 9 5) (2 9 6) (3 9 7) (4 9 8))

Benutzer => (py-zip '((1 9 5) (2 9 6) (3 9 7) (4 9 8))

((1 2 3 4) (9 9 9 9) (5 6 7 8))


Wie ist das besser als nur "Karte" zu verwenden? Und wozu dient ein Makro hier?
Dave Newton
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.