2014-01-25 1 views
2

Учитывая набор элементов [z,a,b,c] Я хочу, чтобы найти «декартово власть» (декартово произведение с собой п раз), но только те результаты, которые имеют z в них. Например:Частичное декартово произведение (убедитесь, что одно значение в каждом наборе)

normal_values = ["a","b","c"] 
p limited_cartesian(normal_values, "z", 2) 
#=> [ 
#=> ["z", "z"] 
#=> ["z", "a"] 
#=> ["z", "b"] 
#=> ["z", "c"] 
#=> ["a", "z"] 
#=> ["b", "z"] 
#=> ["c", "z"] 
#=> ] 

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

def limited_cartesian(values, special, power) 
    [special, *values].repeated_permutation(power) 
        .select{ |prod| prod.include?(special) } 
end 
+0

Действительно ли '' z'' находится в 'normal_values'? –

+0

@mu Это может быть, если вы этого хотите; Я вытащил его, потому что он обрабатывается специально, и в моем фактическом коде это то, что я впрыскиваю в массив не нормальных значений. – Phrogz

+0

'limited_cartesian (normal_values," z ", 3) .size => 37' !! Вероятно, вам известно (из ответа на связанный с вами вопрос, который вы задали недавно), что первые две строки «limited_cartesian» выше могут быть заменены на «toomany = [special, * values] .repeated_permutation (power)». –

ответ

2

Редактировать: С v3.0 У меня наконец-то есть что-то уважительное. Как обычно, ключ искал проблему правильно. Мне пришло в голову, что я могу многократно переставлять normal_values << special, power - 1 раз, то для каждой из этих перестановок будет добавлен еще один элемент. Если перестановка содержала по крайней мере один special, можно было бы добавить любой элемент normal_values << special; в противном случае необходимо добавить special.

def limited_cartesian(values, special, power) 
    all_vals = values + [special] 
    all_vals.repeated_permutation(power-1).map do |p| 
    if p.include?(special) 
     *all_vals.each_with_object([]) { |v,a| a << (p + [v]) } 
    else 
     p + [special] 
    end 
    end  
end 

limited_cartesian(values, 'z', 1) 
    # [["z"]] 

limited_cartesian(values, 'z', 2) 
    # => [["a", "z"], ["b", "z"], ["c", "z"], 
    #  ["z", "a"], ["z", "b"], ["z", "c"], 
    #  ["z", "z"]] 

limited_cartesian(values, 'z', 3) 
    # => [["a", "a", "z"], ["a", "b", "z"], ["a", "c", "z"], 
    #  ["a", "z", "a"], ["a", "z", "b"], ["a", "z", "c"], 
    #  ["a", "z", "z"], ["b", "a", "z"], ["b", "b", "z"], 
    #  ["b", "c", "z"], ["b", "z", "a"], ["b", "z", "b"], 
    #  ["b", "z", "c"], ["b", "z", "z"], ["c", "a", "z"], 
    #  ["c", "b", "z"], ["c", "c", "z"], ["c", "z", "a"], 
    #  ["c", "z", "b"], ["c", "z", "c"], ["c", "z", "z"], 
    #  ["z", "a", "a"], ["z", "a", "b"], ["z", "a", "c"], 
    #  ["z", "a", "z"], ["z", "b", "a"], ["z", "b", "b"], 
    #  ["z", "b", "c"], ["z", "b", "z"], ["z", "c", "a"], 
    #  ["z", "c", "b"], ["z", "c", "c"], ["z", "c", "z"], 
    #  ["z", "z", "a"], ["z", "z", "b"], ["z", "z", "c"], 
    #  ["z", "z", "z"]] 

Это мой v2.1, который работает, но не очень. Я оставлю это для записи.

def limited_cartesian(values, special, power) 
    ndx = Array(0...power) 
    ndx[1..-1].each_with_object([[special]*power]) do |i,a| 
    ndx.combination(i).to_a.product(values.repeated_permutation(power-i).to_a) 
     .each { |pos, val| a << stuff_special(special, pos, val.dup) } 
    end 
end 

def stuff_special(special, pos, vals) 
    pos.each_with_object(Array.new(pos.size + vals.size)) {|j,r| 
    r[j] = special }.map {|e| e.nil? ? vals.shift : e } 
end 
    # e.g., stuff_special('z', [1,4], ["a","b","c"]) => ["a","z","b","c","z"] 
+0

Выглядит многообещающе, но ему не хватает значений. Для второго примера должно быть 37 результатов, а не 18. Например, '[" z "," z "," z "]' отсутствует, а '[" a "," a "," z "]' , – Phrogz

+0

Ничего себе, это точно не красиво, но это правильно! Я оставлю это еще несколько дней, чтобы увидеть, если кто-то еще придумает более элегантное решение. – Phrogz