Объединить массив массива во все возможные комбинации, только вперед, в Ruby

У меня есть массив массивов, например:

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

Мне нужно объединить эти массивы в строку, содержащую все возможные комбинации всех трех наборов, только вперед. Я видел множество примеров всех возможных комбинаций наборов в любом порядке, это не то, что мне нужно. Например, я не хочу, чтобы какие-либо элементы в первом наборе располагались после второго набора, или какие-либо элементы в третьем наборе располагались перед первым или вторым, и так далее. Итак, для приведенного выше примера вывод будет следующим:

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

Количество массивов и длина каждого набора являются динамическими.

Кто-нибудь знает, как решить эту проблему в Ruby?


person Travis    schedule 08.03.2011    source источник
comment
возможный дубликат нескольких итераций   -  person Andrew Grimm    schedule 05.04.2011
comment
См. Также Создание перестановок из многомерного массива   -  person aidan    schedule 31.03.2016


Ответы (3)


Знайте свой _ 1_:

a = [['1','2'],['a','b'],['x','y']]
a.first.product(*a[1..-1]).map(&:join)
person Andrew Grimm    schedule 08.03.2011
comment
@Travis: Если это ответ на ваш вопрос, вы можете поставить галочку / галочку рядом с вопросом. - person Andrew Grimm; 09.03.2011
comment
У меня не работает: дает только ['1ax', '2by']: / - person bfontaine; 25.02.2012
comment
@AndrewGrimm Ответ с использованием transpose неверен; Я отредактировал ваш ответ, чтобы удалить его. - person Phrogz; 10.04.2012
comment
Также обратите внимание, что вы можете: first, *rest = *a; combos = first.product(*rest).map(&:join); ИМХО, эта дополнительная строка - небольшое улучшение читабельности по сравнению с *a[1..-1]. - person Phrogz; 10.04.2012
comment
Господи, спасибо за этот ответ. Я ломал себе голову больше дня, пытаясь создать эту функциональность, даже не подозревая, что у Ruby уже есть метод для выполнения именно того, что мне нужно. : - / - person jeffdill2; 12.11.2019

Решено с использованием рекурсивного, так называемого подхода «динамического программирования»:

  • Для n-массивов объедините записи первого массива с каждым результатом в оставшихся (n-1) массивах.
  • Для одного массива ответом будет только тот массив

В коде:

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

Вы также можете изменить логику, и осторожно вы сможете реализовать это нерекурсивно. Но рекурсивный ответ довольно прост. :)

person Phrogz    schedule 08.03.2011

Чисто, сократите с помощью продукта:

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"]
person Sply Splyeff    schedule 21.03.2015