Czy w Clojure istnieje łatwy sposób na konwersję między typami list?

92

Często znajduję się przy leniwej liście, kiedy chcę mieć wektor i odwrotnie. Czasami mam też wektor map, kiedy bardzo chciałem mieć zestaw map. Czy są jakieś funkcje pomocnicze, które pomogą mi w konwersji między tymi typami?

appshare.co
źródło

Odpowiedzi:

146

Nie zapominajmy, że zaufany stary intopozwala ci wziąć wszystko, co jest w seqstanie (lista, wektor, mapa, zestaw, posortowana-mapa) i pusty pojemnik, który chcesz wypełnić, i umieścić intoto.

(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"

intoto opakowanie wokół conj, które jest podstawową abstrakcją do wstawiania nowych wpisów odpowiednio do kolekcji w oparciu o typ kolekcji. Zasada, która sprawia, że ​​ten przepływ jest tak przyjemny, polega na tym, że Clojure jest zbudowany na abstrakcyjnych kompozycjach , w tym przypadku intona szczycie conjkolekcji i seq.

Powyższe przykłady nadal dobrze komponowałyby się, gdyby odbiorca był przekazywany w czasie wykonywania: ponieważ bazowe abstrakcje ( seqi conj) są zaimplementowane dla wszystkich kolekcji (i wielu kolekcji Javy), więc wyższe abstrakcje nie muszą się martwić o wielu specjalnych przypadkach narożnych związanych z danymi.

Arthur Ulfeldt
źródło
3
+1 dla do ... warto zauważyć, że działa również z niepustymi oryginalnymi pojemnikami (tj. Gdy chcesz dodać do kolekcji)
mikera
11
Warto również zauważyć, że ponieważ intoużycie conj, działanie (into '() some-seq)da listę, która jest odwrotnością niektórych-seq, ponieważ conjwady na listy.
Chuck
Warto zauważyć, że intowykorzystuje transjenty (dla większości typów sekwencyjnych) w celu uzyskania lepszych charakterystyk wydajności niż większość innych środków konwersji.
Jarred Humphrey,
I teraz działa z przetwornikami, które nie istniały w momencie pisania tej odpowiedzi (nie wiem, czy przejściowe też) (Ta odpowiedź jest na tyle stara, że ​​można zapisać się do przedszkola)
Arthur Ulfeldt
33

vec, seti ogólnie intosą Twoimi przyjaciółmi, aby łatwo „przekonwertować” na inny typ kolekcji.

Jak chcesz przekształcić wektor map w mapę map? Potrzebujesz klucza, czy możesz użyć przykładowego wejścia / oczekiwanego wyjścia?

cgrand
źródło
Przepraszam, chodziło mi o zestaw map .. Teraz poprawiłem pytanie
appshare.co
22

W przypadku wektorów istnieje vecfunkcja

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

Dla leniwych sekwencji jest lazy-seqfunkcja

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

Do zamiany na zbiory jest setfunkcja

user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}
cobbal
źródło
4
Kiedy masz coś nie leniwego dzwoniąc, lazy-seqzamiast po seqprostu dodaje bezużyteczne pośrednictwo. Jeśli naprawdę chcesz zwrócić coś niezerowego, nawet przed pustą kolekcją, to jest sequence. lazy-seqjest w pewnym sensie konstrukcją niskiego poziomu.
cgrand
14

Jeszcze jedna odpowiedź na konwersję z listy do mapy (ze względu na kompletność) - stąd :

(apply hash-map '(1 2 3 4))
;=>{1 2, 3 4}
Sokole Oko
źródło
9

Aby przekonwertować wektor na listę, możesz również użyć for, na przykład:

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

Jeśli nie chcesz manipulować danymi, po prostu użyj seqna wektorze:

=> (seq [1 2 3])
(1 2 3)
Geert-Jan Hut
źródło
Zamiast tego formożesz po prostu zrobić(map identity [1 2 3 4])
siltalau
7

Nie ma potrzeby przekształcania wektora na listę. Clojure potraktuje wektor tak, jak traktuje listę - jako sekwencję - gdy sekwencja jest wymagana. Na przykład,

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

Jeśli chcesz się upewnić, że wektor jest traktowany jako sekwencja, zawiń go w 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)

Jeśli masz wektor map i potrzebujesz zestawu map, nie ma znaczenia, że ​​wektor zawiera mapy. Po prostu konwertujesz wektor na zestaw jak zwykle:

user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}
Miniaturka
źródło