Czy istnieje odpowiednik funkcji Zip w Clojure Core lub Contrib?


130

W Clojure chcę połączyć dwie listy, aby uzyskać listę par,

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

W Haskell lub Ruby funkcja nazywa się zip . Wdrożenie go nie jest trudne, ale chciałem się upewnić, że nie brakuje mi funkcji w Core lub Contrib.

W Core istnieje przestrzeń nazw zip , ale jest opisywana jako zapewniająca dostęp do techniki funkcjonalnej Zipper, która nie wydaje się być tym, czego szukam.

Czy istnieje równoważna funkcja łączenia 2 lub więcej list w ten sposób w Core?

Jeśli nie, to czy dzieje się tak dlatego, że istnieje idiomatyczne podejście, które sprawia, że ​​funkcja jest niepotrzebna?


Odpowiedzi:


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

robi co chcesz:

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

Haskell potrzebuje kolekcję zipWith( zipWith3, zipWith4...) funkcjonuje, bo wszystko trzeba być określonego typu ; w szczególności należy ustalić liczbę akceptowanych przez nie list wejściowych. (The zip, zip2, zip3, ... rodzina może być traktowane jako specjalizacji zipWithrodziny do wspólnej przypadku użycia z tupling).

W przeciwieństwie do tego Clojure i inne Lispy mają dobre wsparcie dla funkcji zmiennej arity; mapjest jednym z nich i może być używany do „podkręcania” w sposób podobny do Haskella

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

Idiomatycznym sposobem budowania „krotki” w Clojure jest skonstruowanie krótkiego wektora, jak pokazano powyżej.

(Dla kompletności, zwróć uwagę, że Haskell z kilkoma podstawowymi rozszerzeniami dopuszcza zmienne funkcje aryczności; używanie ich wymaga jednak dobrego zrozumienia języka, a waniliowy Haskell 98 prawdopodobnie w ogóle ich nie obsługuje, dlatego preferowane są funkcje o ustalonej liczbie znaków dla biblioteki standardowej.)


8
Zauważ, że zachowuje się to inaczej niż zipwtedy, gdy kolekcje nie są tej samej długości. Ruby będzie kontynuować przetwarzanie i dostarczać nilpliki do krótszej kolekcji, podczas gdy Clojure przestanie przetwarzać, gdy jedna z kolekcji zostanie wyczerpana.
Nate W.

@NateW. Dobrze to zauważyć, dzięki. In Haskell zipzachowuje się mappod tym względem jak Clojure's .
Michał Marczyk

1
Czy mogę prosić o odniesienie do funkcji Haskella o zmiennej arity?
Teodor

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

lub bardziej ogólnie

(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

aby dać ci dokładnie to, czego chciałeś, mapowanie listmiędzy dwiema listami da ci listę list, jak w twoim przykładzie. Myślę, że wielu Clojurian miałoby tendencję do używania do tego wektorów, chociaż zadziała to ze wszystkim. a wejścia nie muszą być tego samego typu. map tworzy z nich sekwencje, a następnie odwzorowuje sekwencje, więc wszelkie dane wejściowe, które można sekwencjonować, będą działać dobrze.

(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
Myślę, że masz na myśli mapę skrótu i ​​zestaw skrótu zamiast mapy i zestawu.
cgrand

3

Wbudowaną metodą byłaby po prostu funkcja „przeplot”:

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

6
aby osiągnąć cel PO należy dodać(partition 2 (interleave [1 2 3 4][5 6 7 8]))
skuro

tak - Wygląda na to, że nie przyjrzałem się pożądanemu wynikowi PO zbyt dokładnie.
lsh

-1

Istnieje funkcja zwana zipmap, która może mieć podobny efekt (zipmap (1 2 3)(4 5 6)) Wynik jest przepływami: {3 6, 2 5, 1 4}


zipmap zwraca mapę, która nie gwarantuje zamówienia
Ilya Shinkarenko

-2

# (zastosuj listę map%) transponuje macierz, tak jak funkcja zip * w Pythonie. Jako definicja makra:

user => (defmacro py-zip [lst] `(zastosuj listę map ~ lst))

# 'user / py-zip

user => (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))

user => (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))


Jak to jest lepsze niż zwykłe używanie „mapy”? A jaki jest tu sens makra?
Dave Newton,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.