The Enumerable#slice_before
method is quite useful, and it does exactly what it says on the tin - slice an array before an element if a certain condition on the element is met. For example, I am using it to group certain numbers to the following ones.
In my case, the IDs 0xF0
to 0xFB
should be grouped with the IDs that come after them, including multiple of these IDs in a row (they are "modifier" flags in the thing I'm making). I'm doing it like this:
# example code (for SSCCE)
code = '00FF1234F0AAF0BBF0CCCCF3F4F5AAAAAA'.split('').each_slice(2).map{|n| n.join.to_i 16 }
# grouping the modifiers (more may be added later, so array is used)
code = code.slice_before {|tkn| ![*0xF0..0xFB].include? tkn }.to_a
The result of code
after this is
[[0], [255], [18], [52, 240], [170, 240], [187, 240], [204], [204, 243, 244, 245], [170], [170], [170]]
However, the desired result is
[[0], [255], [18], [52], [240, 170], [240, 187], [240, 204], [204], [243, 244, 245, 170], [170], [170]]
I found this entry on bugs.ruby-lang.org, and the response was
The main reason [that this is not implemented] is no one requested.
I have not enough time to implement it now.
Therefore, how can I implement it myself?
It's not the elegant one-liner I'd like to have, but this gets the job done :)
target = []
code.each do |i|
# if there is a previous element and it was one of the "modifiers"
if target.last && [*0xF0..0xFB].include?(target.last.last)
# append it to the current subarray
target.last << i
else
# otherwise, append a new subarray
target << [i]
end
end
You'll find the desired array in target
with code
being unchanged.