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"]]]

这只能正确处理数组长度为 12 的情况。为了使这个更健壮,我们可以检查我们是否只在 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"]]]