How do I use "slice_before" with initial_state in Ruby 1.9?

ruby-1.9, ruby-1.9.3

Solution

The `initial_state` is typically a state hash that stores key-value pairs.

To write your code using a state hash:

a.slice_before(sum: 0) do |elem, state|
  state[:sum] += elem
  if state[:sum] > 3
    # Reset the sum, so we'll get more elements
    state[:sum] = 0  
  end
end.to_a

The `initial_state` must respond to the `#dup` method, because it is duplicated on each loop.

The reason `Fixnum` doesn't work is because it doesn't respond to `#dup`. A Fixnum wouldn't work because it can't keep track of state on each loop.

Problem

I saw Ruby 1.9 has a new enumerator, `slice_before`. The API docs are pretty cryptic. In particular I'm baffled by the variation that takes an `initial_state` value. For example, I want to split an array with numbers into sub-arrays whenever the progressive sum of the elements exceeds some value: ``` a = [1,2,0,1,2,3] a.slice_before(0) do |elem, sum| sum += elem sum > 3 end.to_a ``` Expected output: ``` [[1,2,0], [1,2], [3]] ``` I'm thinking the sum is like a "carry" or "memo" as in `inject` but that doesn't seem to pan out. The glitch in this code is a cryptic error: ``` TypeError: can't dup Fixnum from (irb):43:in `each' ``` It looks like `slice_before` doesn't accept a `Fixnum` as initial value. Why? Ruby bug?. I can work around this by keeping my own state variable, but it's not quite the beautiful Ruby semantic I was looking for. ``` sum = 0 a.slice_before do |elem| sum += elem sum > 3 && sum = 0 end.to_a # => [[1, 2, 0], [1, 2], [3]] ``` So is `initial_state` usable for this purpose, or not? The examples in the docs seem to be mostly about text processing. I'm using Ruby 1.9.3p194.

Original source