Arrays 给定数组的散列,如何使用每个可能的组合创建散列数组
给定一个散列,其值包含长度不等的数组Arrays 给定数组的散列,如何使用每个可能的组合创建散列数组,arrays,ruby,hash,Arrays,Ruby,Hash,给定一个散列,其值包含长度不等的数组 {a: [1, 2, 3], b: [1, 2], c: [1]} 是否可以创建一个包含相同键的散列数组,其中包含如下所示的单个值的所有排列,而无需嵌套多个循环 [ {a: 1, b: 1, c: 1}, {a: 1, b: 2, c: 1}, {a: 2, b: 1, c: 1}, {a: 2, b: 2, c: 1}, {a: 3, b: 2, c: 1}, {a: 3, b: 2, c: 1} ] 我们为每个键使用嵌套的ea
{a: [1, 2, 3], b: [1, 2], c: [1]}
是否可以创建一个包含相同键的散列数组,其中包含如下所示的单个值的所有排列,而无需嵌套多个循环
[
{a: 1, b: 1, c: 1},
{a: 1, b: 2, c: 1},
{a: 2, b: 1, c: 1},
{a: 2, b: 2, c: 1},
{a: 3, b: 2, c: 1},
{a: 3, b: 2, c: 1}
]
我们为每个键使用嵌套的
each
循环来实现这一点,但这在很大程度上看起来很糟糕。实际数据包含更多的键。有很多方法可以做到这一点。就个人而言,我喜欢@Marcin Kołodziej解决方案的紧凑性和有效性,然而,对于新手来说,它可能看起来有点神秘
keys = hash.keys
hash.values.inject(:product).map do |p|
Hash[keys.zip(p.flatten)]
end
另一种解决方法是手动迭代散列并构建数组:
hash = { a: [1, 2, 3], b: [1, 2], c: [1] }
out = []
hash.each do |key, values|
if out.empty?
out = values.map { |v| { key => v } }
else
new_out = []
out.each do |o|
new_out += values.map { |v| o.merge(key => v) }
end
out = new_out
end
end
out
# [{:a=>1, :b=>1, :c=>1}, {:a=>1, :b=>2, :c=>1}, {:a=>2, :b=>1, :c=>1}, {:a=>2, :b=>2, :c=>1}, {:a=>3, :b=>1, :c=>1}, {:a=>3, :b=>2, :c=>1}]
注意第二步中的中间计算:
first.product(*rest)
#=> [[[:a, 1], [:b, 1], [:c, 1]],
# [[:a, 1], [:b, 2], [:c, 1]],
# [[:a, 2], [:b, 1], [:c, 1]],
# [[:a, 2], [:b, 2], [:c, 1]],
# [[:a, 3], [:b, 1], [:c, 1]],
# [[:a, 3], [:b, 2], [:c, 1]]]
第一个问题:你试过什么?提示:还有。@tadman zip不好。如果数组大小不同,则使用以下键压缩每个键的值会产生nils。这给了我想要的值:
hsh[:a].product(hsh[:b]).product(hsh[:c]).map(&:flatte)
,现在我只需要弄清楚如何做到这一点,而不必手动获取乘积并对每个键进行展平,并在新的哈希数组中将每个值应用到其正确的键上。你在谈论排列或组合吗?或者你甚至不知道它们是什么意思?我不是新手,只是面对着一大堆杂乱无章的传统意大利面代码
first.product(*rest)
#=> [[[:a, 1], [:b, 1], [:c, 1]],
# [[:a, 1], [:b, 2], [:c, 1]],
# [[:a, 2], [:b, 1], [:c, 1]],
# [[:a, 2], [:b, 2], [:c, 1]],
# [[:a, 3], [:b, 1], [:c, 1]],
# [[:a, 3], [:b, 2], [:c, 1]]]