Ruby按可变条件划分数组数组
Ruby divide an array of arrays by variable condition
假设我有这样一个数组:
arr=[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"],
["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"], ["1"], ["2"],
["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]
即一系列长度为 1 的子列表(1 个或多个)后跟一系列长度大于 1 的子列表(1 个或多个)。
我想将该列表分为:
[[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"]],
[["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]],
[["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]
即,长度为 1 的子列表与以下长度大于 1 的子列表合并为这些子列表的单个子列表。
这个有效:
data = []
while arr.length > 0
tmp = []
while arr.length > 0 && arr[0].length() == 1
tmp << arr.shift
end
while arr.length > 0 && arr[0].length() > 1
tmp << arr.shift
end
data << tmp
end
p data
# [[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"]], [["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]], [["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]
但这似乎非常笨拙。是否有 .groupby
或 flip/flop 或某种形式的 Ruby 枚举器我缺少以更轻松地执行此操作?
作为对@dawg 答案的改进,如果我们传递给 :slice_when
的块检查 b
的长度是否大于 a
的长度:
data = arr.slice_when { |a, b| b.length < a.length }.to_a
结果是:
[[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"]],
[["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]],
[["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]
这只能正确处理数组长度为 1
或 2
的情况。为了使这个更健壮,我们可以检查我们是否只在 b
的长度为 1
.
时才这样做
data = arr.slice_when { |a, b| b.length == 1 && b.length < a.length }.to_a
现在,如果:
arr = [["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"], ["1", "3", "4"], ["1", "1"],
["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"], ["1"], ["2"],
["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]
结果是:
[[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"], ["1", "3", "4"], ["1", "1"]],
[["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]],
[["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]
假设我有这样一个数组:
arr=[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"],
["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"], ["1"], ["2"],
["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]
即一系列长度为 1 的子列表(1 个或多个)后跟一系列长度大于 1 的子列表(1 个或多个)。
我想将该列表分为:
[[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"]],
[["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]],
[["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]
即,长度为 1 的子列表与以下长度大于 1 的子列表合并为这些子列表的单个子列表。
这个有效:
data = []
while arr.length > 0
tmp = []
while arr.length > 0 && arr[0].length() == 1
tmp << arr.shift
end
while arr.length > 0 && arr[0].length() > 1
tmp << arr.shift
end
data << tmp
end
p data
# [[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"]], [["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]], [["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]
但这似乎非常笨拙。是否有 .groupby
或 flip/flop 或某种形式的 Ruby 枚举器我缺少以更轻松地执行此操作?
作为对@dawg 答案的改进,如果我们传递给 :slice_when
的块检查 b
的长度是否大于 a
的长度:
data = arr.slice_when { |a, b| b.length < a.length }.to_a
结果是:
[[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"]],
[["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]],
[["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]
这只能正确处理数组长度为 1
或 2
的情况。为了使这个更健壮,我们可以检查我们是否只在 b
的长度为 1
.
data = arr.slice_when { |a, b| b.length == 1 && b.length < a.length }.to_a
现在,如果:
arr = [["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"], ["1", "3", "4"], ["1", "1"],
["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"], ["1"], ["2"],
["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]
结果是:
[[["1"], ["1"], ["2", "2"], ["2.1", "0.8"], ["2.2", "0.2"], ["1", "3", "4"], ["1", "1"]],
[["1"], ["2", "3"], ["2", "0.8"], ["2", "0.4"]],
[["1"], ["2"], ["1", "0.8"], ["2", "0.4"], ["3", "0.3"]]]