Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Ruby divide an array of arrays by variable condition

Suppose I have an array like this:

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

ie, a series of sublist (1 or more) of length 1 followed by a series of sublists (1 or more) of length greater than 1.

I want to divide that list into:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

ie, the sub lists of length 1 combined with the following sublists of length greater than 1 into a single sublist of those sublists.

This works:

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

But that seems super clumsy. Is there a .groupby or flip/flop or some form of Ruby enumerator I am missing to do this more easily?

>Solution :

As an improvement on @dawg’s answer, if the block we pass to :slice_when checks for the length of b being greater than the length of a:

data = arr.slice_when { |a, b| b.length < a.length }.to_a

Result is:

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

To make this more robust, we can check that we’re only doing this when b has length 1.

data = arr.slice_when { |a, b| b.length == 1 && b.length < a.length }.to_a

Now, if:

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

The result is:

[[["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"]]]
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading