Gibt es in Clojure eine einfache Möglichkeit, zwischen Listentypen zu konvertieren?

92

Ich benutze oft eine faule Liste, wenn ich einen Vektor möchte, und umgekehrt. Manchmal habe ich auch einen Kartenvektor, wenn ich wirklich einen Kartensatz haben wollte. Gibt es Hilfsfunktionen, mit denen ich zwischen diesen Typen konvertieren kann?

appshare.co
quelle

Antworten:

144

Vergessen wir nicht, dass Sie mit Trusty Old intoalles seqMögliche (Liste, Vektor, Karte, Satz, sortierte Karte) und einen leeren Behälter, den Sie füllen möchten, nehmen und ablegen intokönnen.

(into [] '(1 2 3 4)) ==> [1 2 3 4]         "have a lazy list and want a vector"
(into #{} [1 2 3 4]) ==> #{1 2 3 4}        "have a vector and want a set"
(into {} #{[1 2] [3 4]}) ==> {3 4, 1 2}    "have a set of vectors want a map"
(into #{} [{1 2} {3 4}]) ==> #{{1 2} {3 4}} "have a vector of maps want a set of maps"

intoist ein Wrapper conj, der die Basisabstraktion zum Einfügen neuer Einträge in eine Sammlung basierend auf dem Typ der Sammlung darstellt. Das Prinzip, das diesen Fluss so schön macht, ist, dass Clojure auf komponierbaren Abstraktionen aufbaut , in diesem Fall intoüber conjder Sammlung und seq.

Die obigen Beispiele lassen sich immer noch gut zusammensetzen, wenn der Empfänger zur Laufzeit übergeben wird: Da die zugrunde liegenden Abstraktionen ( seqund conj) für alle Sammlungen (und auch für viele Sammlungen von Java) implementiert sind, müssen sich die höheren Abstraktionen keine Sorgen machen über viele spezielle datenbezogene Eckfälle.

Arthur Ulfeldt
quelle
3
+1 für in ... erwähnenswert, dass es auch mit nicht leeren Originalbehältern funktioniert (dh wenn Sie einer Sammlung hinzufügen möchten)
mikera
11
Es ist auch erwähnenswert, dass , weil intoAnwendungen conj, tun (into '() some-seq)eine Liste erhalten , die das ist umgekehrt irgend-Seq, weil conjconses auf Listen.
Chuck
Es ist erwähnenswert, dass intoTransienten (für die meisten Seq-Typen) für bessere Leistungseigenschaften als die meisten anderen Konvertierungsmittel verwendet werden.
Jarred Humphrey
Und es funktioniert jetzt mit Schallköpfen, die zu dem Zeitpunkt, als diese Antwort geschrieben wurde, noch nicht existierten (ich weiß auch nicht, ob es Transienten gab) (Diese Antwort ist alt genug, um sich in den Kindergarten einzuschreiben)
Arthur Ulfeldt
33

vec, setUnd in der Regel intosind Ihre Freunde einfach „Convert“ in einer anderen Sammlung Typ.

Wie möchten Sie einen Kartenvektor in eine Kartenkarte umwandeln? Sie benötigen einen Schlüssel. Können Sie die Beispieleingabe / erwartete Ausgabe verwenden?

cgrand
quelle
Entschuldigung, ich meinte eine Reihe von Karten. Ich habe die Frage jetzt geändert
appshare.co
22

Für Vektoren gibt es die vecFunktion

user=> (vec '(1 2 3))
[1 2 3]

Für faule Sequenzen gibt es die lazy-seqFunktion

user=> (lazy-seq [1 2 3])
(1 2 3)

Für die Umwandlung in Mengen gibt es die setFunktion

user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}
Cobbal
quelle
4
Wenn Sie etwas nicht faul anrufen, lazy-seqanstatt seqnur eine nutzlose Indirektion hinzuzufügen. Wenn Sie wirklich etwas zurückgeben möchten, das nicht gleich Null ist, gibt es auch keine leeren Sammlungen sequence. lazy-seqist etwas von einem Low-Level-Konstrukt.
Cgrand
14

Noch eine Antwort für die Konvertierung von einer Liste in eine Karte (der Vollständigkeit halber) - von hier aus :

(apply hash-map '(1 2 3 4))
;=>{1 2, 3 4}
Falkenauge
quelle
9

Um einen Vektor in eine Liste zu konvertieren, können Sie auch Folgendes verwenden for:

=> (for [i [1 2 3 4]] i)
(1 2 3 4)

Wenn Sie die Daten nicht bearbeiten möchten, verwenden Sie einfach seqden Vektor:

=> (seq [1 2 3])
(1 2 3)
Geert-Jan Hut
quelle
Stattdessen forkönnten Sie einfach tun(map identity [1 2 3 4])
Siltalau
7

Es ist nicht erforderlich , einen Vektor in eine Liste zu konvertieren . Clojure behandelt einen Vektor wie eine Liste - als Sequenz -, wenn eine Sequenz erforderlich ist. Beispielsweise,

user=> (cons 0 [1 2 3])
(0 1 2 3)

Wenn Sie sicherstellen müssen, dass der Vektor als Sequenz behandelt wird, wickeln Sie ihn ein in seq:

user=> (conj [1 2 3] 0) ; treated as a vector
[1 2 3 0]

user=> (conj (seq [1 2 3]) 0) ; treated as a sequence
(0 1 2 3)

Wenn Sie einen Kartenvektor haben und eine Reihe von Karten möchten, spielt es keine Rolle, dass der Vektor Karten enthält. Sie konvertieren den Vektor einfach wie gewohnt in eine Menge:

user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}
Miniaturansicht
quelle