2012-08-03 19 views
7

Ich bin neu zu Scala, hatte sehr begrenzte Erfahrung mit funktionalen Programmierung durch Haskell.Erstellen einer Liste aller Paare

Ich möchte versuchen, eine Liste aller möglichen Paare zusammenzustellen, die aus einer einzigen Eingabeliste aufgebaut sind. Beispiel:

val nums = List[Int](1, 2, 3, 4, 5) // Create an input list 
val pairs = composePairs(nums)  // Function I'd like to create 

// pairs == List[Int, Int]((1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1) ... etc) 

Ich versuchte zip für jedes Element mit der ganzen Liste mit, in der Hoffnung, dass es den einen Punkt über die gesamte würde dupliziert. Es hat nicht funktioniert (nur das erste mögliche Paar). Ich bin nicht sicher, wie man ein Element wiederholt (Haskell macht es mit cycle und take, glaube ich), und ich hatte Schwierigkeiten, der Dokumentation auf Scala zu folgen.

Das lässt mich denken, dass es wahrscheinlich eine prägnantere, funktionellere Möglichkeit gibt, die gewünschten Ergebnisse zu erzielen. Hat jemand eine gute Lösung?

+3

Es ist sehr hilfreich, um die Terminologie für den Betrieb Sie ausführen wollen zu lernen. In diesem Fall versuchen Sie, das Produkt der Liste mit sich selbst zu finden. Schau dir das an: http://stackoverflow.com/questions/8217764/cartesian-product-of-tow-lists – Marcin

+0

@Marcin Danke. Ich habe einen der größten Stolpersteine ​​gefunden, um einen Grad an funktionaler Programmierung zu lernen, ist die neue Terminologie. – KChaloux

+0

Kreuzprodukt? Wie kartesisches Produkt? Wenn Spark hier relevant ist, dann ist [diese Antwort] (http://stackoverflow.com/a/26565173/1175496) ebenfalls relevant –

Antwort

20

Wie wäre es damit:

val pairs = for(x <- nums; y <- nums) yield (x, y) 
+0

Funktioniert spektakulär. Ich bin mir nicht ganz sicher * warum * es funktioniert. Ist 'für (x <- nums; y <- nums)' wie eine prägnante Art, 'für (x <- nums) für (y <- nums)' zu sagen? – KChaloux

+6

@KChaloux: Es ist syntaktischer Zucker für 'nums.flatMap (x => nums.map ((x, _)))' ', was im Wesentlichen' nums.map (x => nums.map ((x, _))) .flatten', wenn das hilft. –

+0

@dbyrne Es ist definitiv ein Einblick, den ich verwenden könnte. – KChaloux

1

Hier ist eine andere Version der Karte mit und abflachen

val pairs = nums.flatMap(x => nums.map(y => (x,y)))

List[(Int, Int)] = List((1,1), (1,2), (1,3), (1,4), (1,5), (2,1), (2,2), (2,3), (2,4), (2,5), (3,1), (3,2), (3,3), (3,4), (3,5), (4,1), (4,2), (4,3), (4,4), (4,5), (5,1), (5,2) (5,3), (5,4), (5,5))

Dies kann dann leicht in eine composePairs Funktion eingewickelt werden, wenn Sie mögen:

def composePairs(nums: Seq[Int]) = 
    nums.flatMap(x => nums.map(y => (x,y))) 
+2

Verwenden Sie besser 'flatMap (...)' anstelle von 'map (...). Flatten'. –

2

Für diejenigen von Ihnen, die Duplikate nicht wollen:

val uniquePairs = for { 
     (x, idxX) <- nums.zipWithIndex 
     (y, idxY) <- nums.zipWithIndex 
     if idxX < idxY 
    } yield (x, y) 

val nums = List(1,2,3,4,5) 
uniquePairs: List[(Int, Int)] = List((1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)) 
+0

Sie möchten '<='. Ihre Ausgabe fehlt (z. B.) '(1,1)' –

+0

Man kann '(x, x)' in einigen Fällen als doppelt sehen. Hinzufügen von '<=' oder Ersetzen zu '>', '> =' sollte offensichtlich sein. – keos

Verwandte Themen