在Ruby中,我该如何解决这个问题:
[
1,
["green", "blue", "black"],
[ ["1", "2"], ["3"], ["4", "5"] ]
]
到此?
[
[1, "green", "1"],
[1, "green", "2"],
[1, "blue", "3"],
[1, "black", "4"],
[1, "black", "5"],
]
我试过.zip但没有运气。非常感谢任何帮助,当然我正在寻找一个高效的解决方案。
答案 0 :(得分:3)
模式对我来说并不完全清楚,但这会得到您提供的示例的预期输出:
data[1].
zip(data[2]).
flat_map { |x, ys| [x].product(ys) }.
map { |zs| [data[0], *zs] }
#=> [[1, "green", "1"], [1, "green", "2"], [1, "blue", "3"],
# [1, "black", "4"], [1, "black", "5"]]
答案 1 :(得分:2)
我们得到了
arr = [1, ["green", "blue", "black"], [ ["1", "2"], ["3"], ["4", "5"] ]]
以下是获得所需结果的两种方法。
<强>#1 强>
arr[1].flat_map.with_index { |color,i| [arr[0]].product([color], arr[2][i]) }
#=> [[1, "green", "1"], [1, "green", "2"], [1, "blue", "3"],
# [1, "black", "4"], [1, "black", "5"]]
步骤如下。
enum0 = arr[1].flat_map
#=> #<Enumerator: ["green", "blue", "black"]:flat_map>
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: ["green", "blue", "black"]:flat_map>:with_index>
enum1
可以被视为复合枚举器。我们可以看到enum1
生成的值,并通过将其转换为数组传递给块。
enum1.to_a
#=> [["green", 0], ["blue", 1], ["black", 2]]
生成第一个值并传递给块,分配块变量并执行块计算。
color, i = enum1.next
#=> ["green", 0]
color
#=> "green"
i #=> 0
[arr[0]].product([color], arr[2][i])
#=> [1].product(["green"], )
#=> [[1, "green", "1"], [1, "green", "2"]]
enum1
生成的其余两个元素的计算类似。
替代方法是复制arr[2]
并移动dup的元素:
a2 = arr[2].dup
arr[1].flat_map { |color,i| [arr[0]].product([color], a2.shift) }
<强>#2 强>
arr[1].zip(arr[2]).flat_map { |color, a| [arr[0]].product([color], a) }
#=> [[1, "green", "1"], [1, "green", "2"], [1, "blue", "3"],
# [1, "black", "4"], [1, "black", "5"]]
步骤如下。
b = arr[1].zip(arr[2])
#=> [["green", ["1", "2"]], ["blue", ["3"]], ["black", ["4", "5"]]]
b[0]
传递给flat_map
并分配块变量并执行块计算。
color, a = b[0]
#=> ["green", ["1", "2"]]
color
#=> "green"
a #=> ["1", "2"]
[arr[0]].product([color], a)
#=> [["1"]].product(["green"], ["1", "2"])
#=> [[1, "green", "1"], [1, "green", "2"]]
将b
的其余元素传递给map
后,Enumerable#flat_map会返回所需的数组。
答案 2 :(得分:1)
与提议的解决方案相比,我需要更通用和灵活的解决方案(我的不好,我应该更清楚地了解要求),所以我想出了以下内容:
class Array
def transpose_rows
arys = self.select{|el| el.is_a?(Array)}
if arys.size == 0
[self]
else
result = []
(arys.map(&:size).max || 1).times.map{ |i|
self.map { |r|
r.is_a?(Array) ? r[i] : r
}.transpose_rows.map{|r| result << r}
}
result
end
end
end
初始规范是数组中的每个元素都是一个值或另一个深度不同的数组。每个子阵列将 depth-1 的子阵列的值“爆炸”为任意数量的“子值”。结果应该是一组行,列出从原始数组派生的所有组合。
提出的其他解决方案适用于我发布的原始数组,这只是一个示例,而这个解决方案适用于更复杂的方案,如下所示:
[
2,
[3,4,5],
6,
[7,8,9],
[ [11,22], [33], [44,55] ],
[0, 1, 2],
[ [66], [77], [nil,99] ],
4
].transpose_rows
# => [
# [2, 3, 6, 7, 11, 0, 66, 4],
# [2, 3, 6, 7, 22, 0, nil, 4],
# [2, 4, 6, 8, 33, 1, 77, 4],
# [2, 5, 6, 9, 44, 2, nil, 4],
# [2, 5, 6, 9, 55, 2, 99, 4]
# ]