How to split an array by a condition on adjacent elements into a limited number of partitions
There's probably a better way to do this but my first thought is...
break_done = false
ary.slice_when { |i, j| (break_done = i > j) unless break_done }.to_a
#=> [[1, 3, 6, 7, 10], [9, 11, 13, 7, 24]]
I'm not sure you'll find this more elegant, but it prevents the split-and-rejoin maneuver:
def split(ary)
split_done = false
ary.slice_when do |i, j|
!split_done && (split_done = yield(i, j))
end.to_a
end
Usage:
ary = [1, 3, 6, 7, 10, 9, 11, 13, 7, 24]
split(ary){ |i, j| i > j }
#=> [[1, 3, 6, 7, 10], [9, 11, 13, 7, 24]]
Update:
Some may find this variant more readable. #chunk_while
is the inverse of #split_when
and then I just applied De Morgan's Law to the block.
def split(ary)
split_done = false
ary.chunk_while do |i, j|
split_done || !(split_done = yield(i, j))
end.to_a
end
Here's another version. Not particularly elegant or efficient, but is quite efficient (see comments).
break_point = ary.each_cons(2).with_index do |(a, b), idx|
break idx if b < a # plug your block here
end + 1
[
ary.take(break_point),
ary.drop(break_point)
] # => [[1, 3, 6, 7, 10], [9, 11, 13, 7, 24]]