2012-01-26 2 views
5

У меня этот знакомый вопрос, который выглядит как перестановка/сочетание математического мира.Как сочетать/переставлять в рубине?

Как я могу получить следующее через ruby?

badges = "1-2-3" 

badge_cascade = [] 
badges.split("-").each do |b| 
    badge_cascade << b 
end 

Gives: => ["1", "2", "3"] 

But I want it to be is: 

=> ["1", "2", "3", 
    "1-2", "2-3", "3-1", "2-1", "3-2", "1-3", 
    "1-2-3", "2-3-1", "3-1-2"] 
+1

ожидаемые значения для перестановок 3-х элементов выглядят странно, только 3 элемента? Я считаю, 6. – tokland

ответ

7

Функциональный подход:

bs = "1-2-3".split("-") 
strings = 1.upto(bs.size).flat_map do |n| 
    bs.permutation(n).map { |vs| vs.join("-") } 
end 
#=> ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"] 
5

Вы определены использовать Array#permutation метод для того, чтобы получить все перестановки:

arr = "1-2-3".split '-' # => ["1", "2", "3"] 
res = (1..arr.length).reduce([]) { |res, length| 
    res += arr.permutation(length).to_a 
}.map {|arr| arr.join('-')} 

puts res.inspect 
# => ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"] 

Позвольте мне объяснить код:

  1. вы разделяете строку в массив проходя сепаратор '-' в String#split метод

  2. Вам понадобятся все перестановки длиной 1, 2, 3. Диапазон 1..arr.length представляет все эти длины.

  3. Вы собираете массив всех перестановок, используя Enumerable#reduce. вы получите массив массивов здесь:

    [["1"], ["2"], ["3"], ["1", "2"], ["1", "3"], ["2", "1"], ["2", "3"], ["3", "1"], ["3", "2"], ["1", "2", "3"], ["1", "3", "2"], ["2", "1", "3"], ["2", "3", "1"], ["3", "1", "2"], ["3", "2", "1"]] 
    
  4. Вы превращаетесь все подмассива этого массива в строки, используя Array#join с '-' сепаратора внутри Enumerable#map

+0

Обратите внимание, что вы эмулируете существующую абстракцию 'flat_map' с' reduce' + 'concat'. – tokland

1

Array#permutation(n) даст вам все перестановки length n как массив массивов, чтобы вы могли назвать это с каждой длиной между 1 и числом цифр в значками. Последний шаг состоит в том, чтобы сопоставить все эти строки со строками, разделенными -.

badges = "1-2-3" 

badges_split = badges.split('-') 

permutations = [] 

(1..badges_split.size).each do |n| 
    permutations += badges_split.permutation(n).to_a 
end 

result = permutations.map { |permutation| permutation.join('-') } 

Update:Я думаю, что использование Алекса из reduce более элегантный подход, но я оставлю этот ответ здесь теперь в случае полезно.

Смежные вопросы