2012-01-04 2 views
1

Хорошо, я искал в Интернете ответы и также искал часы у своего рубинового программиста, но я не могу разобраться в этом. Я пишу скрипт для создания всех видов комбинаций из элементов в массиве.Ruby Комбинации с элементами массива

ar = ["a","b","c","d"] 

На данный момент я могу сделать эти комбинации:

["a"],["a","b"],["a","b","c"],["a","b","c","d"],["b"],["b","c"],["b","c","d"],["c"],["c","d"],["d"] 

Это нормально, но я не могу найти способ для поиска этих комбинаций, например ["a","c"] or ["a","c","d"] or ["a","d"], и т.д ...

На данный момент мой код выглядит следующим образом:

def combinaties(array) 
    combinaties = [] 
    i=0 
    while i <= array.length-1 
    combinaties << array[i] 
    unless i == array.length-1 
     array[(i+1)..(array.length-1)].each{|volgend_element| 
     combinaties<<(combinaties.last.dup<<volgend_element) 
     } 
    end 
    i+=1 
    end 
end 
+0

какой у вас вопрос ...? – sethvargo

+0

Вы ищете перестановки? Вы можете попробовать это с помощью индексов массива. – three

+1

@three Class Array имеет [метод перестановки] (http://ruby-doc.org/core-1.9.3/Array.html#method-i-permutation). – steenslag

ответ

4

Существует тривиальный-корреспондент (биекция) между такими комбинациями и номерами в [1 .. (2^m - 1)] (m - длина массива).

Рассмотрите такое число n. Это двоичное представление имеет m цифр (включая начальные нули). Позициями цифр, которые являются 1, являются индексы элементов в соответствующей комбинации.

Код будет:

def combinations(array) 
    m = array.length 
    (1...2**m).map do | n | 
    (0...m).select { | i | n[i] == 1 }.map { | i | array[i] } 
    end 
end 
+1

Вы можете использовать побитовое индексирование в целые числа в Ruby, чтобы узнать, является ли определенный бит 1, что приводит к более простому коду: http://stackoverflow.com/a/8535241/220147 –

+0

@MichaelKohl: Нравится? –

+0

Это замечательно! Это трюк! Благодаря! – KenGey

9

Functional подход (потребности рубин> = 1,9), чтобы создать powerset массива (для пустого элемента вы, кажется, не нужно, кроме):

xs = ["a", "b", "c", "d"] 
yss = 1.upto(xs.size).flat_map do |n| 
    xs.combination(n).to_a 
end 

#[ 
# ["a"], ["b"], ["c"], ["d"], 
# ["a", "b"], ["a", "c"], ["a", "d"], ["b", "c"], ["b", "d"], ["c", "d"], 
# ["a", "b", "c"], ["a", "b", "d"], ["a", "c", "d"], ["b", "c", "d"], 
# ["a", "b", "c", "d"], 
#] 
+0

Это похоже на то, что мне нужно! Единственное, что я застрял с Ruby 1.8.6 ... Это для плагина Google SketchUp, над которым я работаю, поэтому обновление Ruby не является вариантом. Спасибо за ответ в любом случае! Приветствия – KenGey

+0

user1130886: это не проблема, используйте https://github.com/marcandre/backports – tokland

2

Или в рубин 1,9

%w(a b c d e).combination(3).to_a 

даст вам все комбинации размеров 3.

+0

Такая же проблема здесь, я застрял с Ruby 1.8.6 ... Спасибо за ответ! – KenGey