22 Stimmen

Wie kann man mehrere Listen in Haskell zippen?

In Python zip Funktion akzeptiert eine beliebige Anzahl von Listen und fügt sie zusammen.

>>> l1 = [1,2,3]
>>> l2 = [5,6,7]
>>> l3 = [7,4,8]
>>> zip(l1,l2,l3)
[(1, 5, 7), (2, 6, 4), (3, 7, 8)]
>>> 

Wie kann ich zip mehrere Listen in Haskell zusammenführen?

39voto

luqui Punkte 58358

Eine Verallgemeinerung von zip kann erreicht werden durch Anwendbare Notation . Es ist ein bisschen unangenehm zu benutzen, wegen des newtype wrapping/unwrapping, aber wenn Sie etwas tun, das nicht mit einer zipWithn für ein einigermaßen kleines n sind Sie wahrscheinlich schon auf einer ausreichend hohen Abstraktionsebene, wo es keine Probleme mit der Notation mehr gibt.

Der Typ ist ZipList a und seine applikative Instanz fügt Listen zusammen. Zum Beispiel:

(+) <$> ZipList [1,2] <*> ZipList [3,4] == ZipList [4,6]

Dies lässt sich durch partielle Anwendung auf Funktionen beliebiger Arität und beliebigen Typs verallgemeinern:

(+) <$> ZipList [1,2]  :: ZipList (Int -> Int)

Sehen Sie, wie (+) hier teilweise angewendet wird?

Wenn es Ihnen nicht gefällt, überall ZipList und getZipList hinzuzufügen, können Sie die Notation leicht nachbilden:

(<$>) :: (a -> b) -> [a] -> [b]
(<$>) = map

(<*>) :: [a -> b] -> [a] -> [b]
(<*>) = zipWith ($)

Dann ist die Notation für zipWith f a b c d ... ist:

f <$> a <*> b <*> c <*> d <*> ...

Die anwendungsbezogene Notation ist eine sehr leistungsfähige und allgemeine Technik, die weit über die Verallgemeinerung des Reißverschlusses hinausgeht. Siehe die Typklassopädie für weitere Informationen zur Anwendbaren Notation.

34voto

newacct Punkte 114757

Sie können eine Liste von Listen transponieren:

>>> import Data.List
>>> transpose [l1,l2,l3]
[[1,5,7],[2,6,4],[3,7,8]]

11voto

tux21b Punkte 82543

Sieht aus, als gäbe es auch eine zip3 ( doc ) und eine zip4 ( doc ) Funktion in Haskell. Aber das zipn scheint wegen des starken Typsystems kompliziert zu sein. Hier ist eine gute Diskussion Das habe ich bei meinen Recherchen herausgefunden.

6voto

David Punkte 8035

GHC unterstützt auch parallele Listenauflösungen :

{-# LANGUAGE ParallelListComp #-}

[(x,y) | x <- [1..3]
       | y <- ['a'..'c']
       ]

==> [(1,'a'),(2,'b'),(3,'c')]

Ich habe es gerade mit bis zu 26 parallelen Variablen getestet, was für alle praktischen Zwecke ausreichend sein sollte.

Es ist allerdings etwas hakelig (und nicht standardisiert). Wenn Sie also etwas Ernsthaftes schreiben wollen, ist ZipList vielleicht die bessere Lösung für Sie.

4voto

Emmanuel Touzery Punkte 8370

Ich denke, es ist wahrscheinlich die am wenigsten elegante Lösung, die vorgeschlagen wurde, aber der Vollständigkeit halber sollte hinzugefügt werden, dass solche Dinge mit Template Haskell möglich sein sollten.

Dies wurde in der Tat in dem, was ich denke, ist die ursprüngliche Template Haskell Papier (Suche zipn im Text) behandelt: http://research.microsoft.com/en-us/um/people/simonpj/Papers/meta-haskell/meta-haskell.pdf

Aber ich glaube, dieser Code hat nie wirklich funktioniert, siehe dies: http://www.haskell.org/pipermail/template-haskell/2003-July/000126.html (Pattern Slices sind nicht implementiert).

Das war 2003 nicht der Fall, aber es ist auch heute noch nicht umgesetzt: http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/template-haskell.html (Pattern Slices werden nicht unterstützt)

Es gibt jedoch eine Implementierung von zipWithN unter Verwendung von Template Haskell: http://www.haskell.org/haskellwiki/Template_Haskell#zipWithN

Ich habe überprüft, dass es mit diesem Testprogramm funktioniert:

{-# LANGUAGE TemplateHaskell #-}
import Zipn

main = do
    let l1 = [1,2,3]
    let l2 = [5,6,7]
    let l3 = [7,4,8]
    print $ $(zipWithN 3) (,,) l1 l2 l3

In das Zipn-Modul habe ich das zipn eingefügt, nur der Übersichtlichkeit halber in zipWithN umbenannt (und daran gedacht, das Pragma TemplateHaskell oben hinzuzufügen). Beachten Sie, dass das N hier tatsächlich zweimal harcodiert ist, weil ich (,,) als die Funktion "mit". Sie müssen die Anzahl der Kommas je nach N ändern.

(,,) steht für \a b c -> (a,b,c)

Ich schätze, dass jemand mit guten Template-Haskell-Kenntnissen (was bei mir derzeit nicht der Fall ist) ein geradliniges zipN mit Template Haskell erstellen könnte.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X