2014-01-25 52 views
2

給定一組項目[z,a,b,c]我想找到「笛卡兒的力量」(笛卡爾乘積自身ñ倍),但只有那些結果,在他們有一個z。例如:局部笛卡爾乘積(確保每1個值)

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

看起來很有前途,但缺少價值。例如,缺少'[「z」,「z」,「z」]',並且'[「a」,「a」,「z」]' 。 – Phrogz

+0

哇,那肯定不是很漂亮,但它是正確的!我會離開這幾天,看看是否有其他人提出一個更優雅的解決方案。 – Phrogz