Question: How to split a Ruby array into subarrays of unequal size using a delimiter

Question

How to split a Ruby array into subarrays of unequal size using a delimiter

Answers 2
Added at 2017-01-05 16:01
Tags
Question

I have the following array:

arr = [0, 1, 1, 2, 3, 1, 0, 0, 1]

Without changing the order of the values, I need to subdivide arr into smaller arrays at every occurrence of 0, such that the result would be:

arr = [ [0, 1, 1, 2, 3, 1], [0], [0, 1] ]

If arr were a string, I could use .split("0") and then prepend the delimiter to each subarray. What would be the most efficient equivalent to .split() in plain Ruby for arrays?

Answers
nr: #1 dodano: 2017-01-05 20:01

Since ActiveSupport defines an Array#split method in Ruby, we can use it as a starting point:

class Array
  def split(value = nil)
    arr = dup
    result = []
    if block_given?
      while (idx = arr.index { |i| yield i })
        result << arr.shift(idx)
        arr.shift
      end
    else
      while (idx = arr.index(value))
        result << arr.shift(idx)
        arr.shift
      end
    end
    result << arr
  end
end

# then, using the above to achieve your goal:
arr = [0, 1, 1, 2, 3, 1, 0, 0, 1]
arr.split(0).map { |sub| sub.unshift(0) }
# => [[0], [0, 1, 1, 2, 3, 1], [0], [0, 1]] 

Note that your verbal phrasing of the algorithm (split and prepend) is what is happening here, but your expected output is different (there's an additional zero because of the way split works).

Do you want to split before each zero? For this you could use slice_before.

Do you want to split but drop empty arrays? This could be done with a quick compact before prepending, but you would lose the [0] subarray.

Do you want to split but drop the first element if empty?

Do you want to split on /0+/?

nr: #2 dodano: 2017-01-05 20:01

Enumerable#slice_before does this exact thing:

arr = [0, 1, 1, 2, 3, 1, 0, 0, 1]
p arr.slice_before(0).to_a
# => [[0, 1, 1, 2, 3, 1], [0], [0, 1]]

See it on repl.it: https://repl.it/FBhg

Source Show
◀ Wstecz