2011-03-08 19 views
27

Tengo una matriz de matrices, así:Combinar conjunto de matriz en todas las combinaciones posibles, sólo hacia adelante, en Ruby

[['1','2'],['a','b'],['x','y']] 

tengo que combinar esas matrices en una cadena que contiene todas las combinaciones posibles de los tres conjuntos, solo hacia adelante. He visto muchos ejemplos de todas las combinaciones posibles de los conjuntos en cualquier orden, eso no es lo que quiero. Por ejemplo, no quiero que ninguno de los elementos en el primer conjunto venga después del segundo conjunto, ni ninguno en el tercer conjunto antes del primero, ni el segundo, y así sucesivamente. Por lo tanto, para el ejemplo anterior, la salida sería:

['1ax', '1ay', '1bx', '1by', '2ax', '2ay', '2bx', '2by'] 

El número de matrices, y la longitud de cada conjunto es dinámica.

¿Alguien sabe cómo resolver esto en Ruby?

+0

posible duplicado de [iteraciones múltiples] (http://stackoverflow.com/questions/5543896/multiple -iterations) –

+0

ver también [Creación de permutaciones de una matriz multi-dimensional] (http://stackoverflow.com/questions/5582481/creating-permutations-from-a-multi-dimensional-array-in-ruby) – aidan

Respuesta

52

Know su Array#product:

a = [['1','2'],['a','b'],['x','y']] 
a.first.product(*a[1..-1]).map(&:join) 
+5

¡Sexytime! Bien hecho. – Phrogz

+0

@Travis: si esto responde a su pregunta, puede marcar la casilla de verificación junto a la pregunta. –

+0

No funciona para mí: solo me da '' ['1ax', '2by'] '':/ – bfontaine

6

Resuelto usando un recursivo, llamado "Dynamic Programming" enfoque:

  • para el n-arrays, se combinan las entradas de la primera matriz con cada resultado en los restantes (n-1) arrays
  • Para una sola matriz, la respuesta es simplemente que el conjunto

En código:

def variations(a) 
    first = a.first 
    if a.length==1 then 
    first 
    else 
    rest = variations(a[1..-1]) 
    first.map{ |x| rest.map{ |y| "#{x}#{y}" } }.flatten 
    end 
end 

p variations([['1','2'],['a','b'],['x','y']]) 
#=> ["1ax", "1ay", "1bx", "1by", "2ax", "2ay", "2bx", "2by"] 

puts variations([%w[a b],%w[M N],['-'],%w[x y z],%w[0 1 2]]).join(' ') 
#=> aM-x0 aM-x1 aM-x2 aM-y0 aM-y1 aM-y2 aM-z0 aM-z1 aM-z2 aN-x0 aN-x1 aN-x2 
#=> aN-y0 aN-y1 aN-y2 aN-z0 aN-z1 aN-z2 bM-x0 bM-x1 bM-x2 bM-y0 bM-y1 bM-y2 
#=> bM-z0 bM-z1 bM-z2 bN-x0 bN-x1 bN-x2 bN-y0 bN-y1 bN-y2 bN-z0 bN-z1 bN-z2 

También podría invertir la lógica, y con cuidado debería poder implementar esto de forma no recursiva. Pero la respuesta recursiva es bastante directa. :)

+1

Muy bien codificarse , mapas y recursión! – macarthy

3

puro, reducir con el producto:

a = [['1','2'],['a','b'],['x','y']] 
a.reduce() { |acc, n| acc.product(n).map(&:flatten) }.map(&:join) 
# => ["1ax", "1ay", "1bx", "1by", "2ax", "2ay", "2bx", "2by"] 
Cuestiones relacionadas