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?

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.


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?


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}}

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}

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)

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}}
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.