Ruby 部分笛卡尔积(确保每组中有一个值)

Ruby 部分笛卡尔积(确保每组中有一个值),ruby,cartesian-product,Ruby,Cartesian Product,给定一组项[z,a,b,c]我想找到“笛卡尔幂”(笛卡尔积本身有n次),但只找到那些具有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,a,b,c]
我想找到“笛卡尔幂”(笛卡尔积本身有n次),但只找到那些具有
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

编辑:使用v3.0,我终于有了一些值得尊敬的东西。通常情况下,关键在于以正确的方式看待问题。我突然想到,我可以反复排列
正常值
'z'
应该在
正常值中吗?@mu如果你想的话,它可能在那里;我把它拔出来是因为它是经过特殊处理的,在我的实际代码中,它是我注入到一个非正常值数组中的东西。
limited\u cartesian(正常值,“z”,3)。size=>37
!!您可能知道(从您最近对相关问题的回答中)上面的
limited\u cartesian
的前两行可以替换为
toomany=[special,*values]。重复排列(power)
。看起来很有希望,但缺少值。第二个例子应该有37个结果,而不是18个。例如,
[“z”,“z”,“z”]
缺失,以及
[“a”,“a”,“z”]
。哇,这确实不漂亮,但它是对的!我会多留几天,看看是否有人能想出一个更优雅的解决方案。
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"]] 
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"]