Combinación de dos matrices en Ruby

82

¿Cuál es la forma Ruby de conseguir seguidores?

a = [1,2]
b = [3,4]

Quiero una matriz:

=> [f(1,3) ,f(1,4) , f(2,3) ,f(2,4)]
pierrotlefou
fuente
@lucasarruda eso no es exactamente lo mismo que pide OP. Zip creará una matriz de [a[0], b[0]]y [a[1], b[1]]. No incluiría [a[0], b[1]]. a.zip(b) => [[1,3],[2,4]]
KNejad
Gracias @KNejad, tienes razón. Borré mi comentario.
lucasarruda

Respuestas:

147

Puede usar productpara obtener el producto cartesiano de las matrices primero y luego recopilar los resultados de la función.

a.product(b) => [[1, 3], [1, 4], [2, 3], [2, 4]]

Entonces puedes usar mapo collectpara obtener los resultados. Son nombres diferentes para el mismo método.

a.product(b).collect { |x, y| f(x, y) }
Aaron Hinni
fuente
El producto solo está integrado a partir de 1.9.
Pesto
7
El producto está en 1.8.7 - Lo uso para hacer exactamente lo que pide Pierr
Chris McCauley
1
@FloatingRock eso es incorrecto, es una combinación, no una permutación. Ver ruby-doc.org/core-2.1.3/Array.html#method-i-product
Josh Diehl
1
@FloatingRock No es así. El primer elemento de cada elemento siempre vendrá de la primera lista, el segundo elemento de la segunda lista, y así sucesivamente. Son todas las combinaciones posibles de elementos, pero nunca se reordenan, por lo que no son permutaciones.
Mark Reed
Y si tienes c = [5,6] yd = [7,8] puedes hacerlo[a,b,c,d].reduce([[]]){|r,e| r=r.product(e)}.map{|x| x.flatten}
xxjjnn
11
a.map {|x| b.map {|y| f(x,y) } }.flatten

Nota: en 1.8.7+ puede agregar 1como argumento para aplanar, por lo que aún obtendrá resultados correctos cuando fdevuelva una matriz.

Aquí hay una abstracción para un número arbitrario de matrices:

def combine_arrays(*arrays)
  if arrays.empty?
    yield
  else
    first, *rest = arrays
    first.map do |x|
      combine_arrays(*rest) {|*args| yield x, *args }
    end.flatten
      #.flatten(1)
  end
end

combine_arrays([1,2,3],[3,4,5],[6,7,8]) do |x,y,z| x+y+z end
# => [10, 11, 12, 11, 12, 13, 12, 13, 14, 11, 12, 13, 12, 13, 14, 13, 14, 15, 12, 13, 14, 13, 14, 15, 14, 15, 16]
sepp2k
fuente
Esto funcionará, aunque no estoy seguro de si es la mejor manera (aunque no puedo pensar en una mejor, así que +1)
Robert Massaioli
Ojalá pudiera +2 por la combinación de una cantidad arbitraria de matrices. ¡Muy genial!
pierrotlefou
También salí con esto ... pero luego supe que debería haber una manera más fácil de hacerlo ... +1 para esto, pero @Aaron Hinni responde que es más limpio
Orlando
5

Facetas tiene lo Array#productque le dará el producto cruzado de matrices. También tiene el alias ** operatorpara el caso de dos matrices. Usando eso, se vería así:

require 'facets/array'
a = [1,2]
b = [3,4]

(a.product b).collect {|x, y| f(x, y)}

Si está utilizando Ruby 1.9, productes una función de matriz incorporada.

pesto
fuente
¿Por qué la gente sigue diciendo que el producto Array # es un 1.9ism? Está en 1.8.7, al menos.
Mark Reed