2012-08-03 33 views
7

Soy nuevo en Scala, ya que he tenido una experiencia muy limitada con la programación funcional a través de Haskell.Componer una lista de todos los pares

Me gustaría intentar componer una lista de todos los pares posibles construidos a partir de una sola lista de entrada. Ejemplo:

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) 

me trató de usar zip en cada elemento de la lista entera, con la esperanza de que duplicaría el único elemento en el conjunto. No funcionó (solo coincidió con el primer par posible). No estoy seguro de cómo repetir un elemento (Haskell lo hace con cycle y take Creo), y he tenido problemas para seguir la documentación en Scala.

Esto me deja pensando que probablemente haya una forma más concisa y funcional de obtener los resultados que quiero. ¿Alguien tiene una buena solución?

+3

Es muy útil para aprender la terminología para la operación que desea realizar. En este caso, está tratando de encontrar el producto de la lista consigo mismo. Mira esto: http://stackoverflow.com/questions/8217764/cartesian-product-of-two-lists – Marcin

+0

@Marcin Gracias. He descubierto que uno de los mayores obstáculos para aprender cualquier grado de programación funcional es aprender la nueva terminología. – KChaloux

+0

producto cruzado? Lo mismo que el producto cartesiano? Si Spark es relevante aquí, entonces [esta respuesta] (http://stackoverflow.com/a/26565173/1175496) también es relevante –

Respuesta

20

¿Qué tal esto:

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

Funciona espectacularmente. No estoy del todo seguro * por qué * aunque funciona. Es 'for (x <- nums; y <- nums) 'como una forma concisa de decir' for (x <- nums) for (y <- nums) '? – KChaloux

+6

@KChaloux: es azúcar sintáctica para 'nums.flatMap (x => nums.map ((x, _)))', que es esencialmente 'nums.map (x => nums.map ((x, _))) .flatten', si eso ayuda. –

+0

@dbyrne Definitivamente es una idea que podría usar. – KChaloux

1

Aquí hay otra versión en el mapa y aplanar

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

Esto entonces se puede envolver fácilmente en una función composePairs si lo desea:

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

Es mejor usar 'flatMap (...)' en lugar de 'map (...). Flatten'. –

2

Para aquellos de ustedes que no quieren duplicados:

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

Quiere '<='. La salida falta (por ejemplo) '(1,1)' –

+0

Uno puede ver '(x, x)' como duplicado en algunos casos. Agregar '<=' o reemplazar a '>', '> =' debería ser obvio. – keos

Cuestiones relacionadas