简体   繁体   中英

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

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?

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

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+/ ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM