如何在Ruby 1.9中使用带有initial_state的"slice_before"?

4
我看到 Ruby 1.9 有一个新的 enumerator,名为 slice_before。然而,API 文档 中描述比较晦涩难懂。
特别是当它接受一个 initial_state 值时,我感到有些困惑。
例如,我想将一个数字数组拆分成多个子数组,每当元素的累加和超过某个值时就进行拆分:
a = [1,2,0,1,2,3]
a.slice_before(0) do |elem, sum|
  sum += elem
  sum > 3
end.to_a

预期输出:

[[1,2,0], [1,2], [3]]

我觉得这个总和就像是“进位”或“备忘”,类似于inject函数,但貌似行不通。
这段代码的故障是一个晦涩的错误:
TypeError: can't dup Fixnum
from (irb):43:in `each'

看来slice_before不接受Fixnum作为初始值。为什么?是Ruby的bug吗?

我可以通过保留自己的状态变量来解决这个问题,但这并不是我所期望的优美的Ruby语义。

sum = 0
a.slice_before do |elem|
  sum += elem
  sum > 3 && sum = 0
end.to_a

# => [[1, 2, 0], [1, 2], [3]]

那么initial_state是否可用于此目的呢?文档中的示例似乎主要是关于文本处理的。我正在使用Ruby 1.9.3p194。

1个回答

4

initial_state通常是一个存储键值对的状态哈希。

使用状态哈希编写代码的方法如下:

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

initial_state必须响应#dup方法,因为它在每次循环中都会被复制。

Fixnum不能工作的原因是它不响应#dup。 Fixnum无法在每个循环中跟踪状态,因此无法使用。


非常有趣。这不是很直观的。谢谢Joel。你是怎么发现这个的? - Wolfram Arnold
有人能解释一下这段代码示例中的第三行吗?为什么布尔值要与(在我看来像)一个赋值进行逻辑与操作? - user25959
是的。我更新了代码,让它更清晰易懂。一般来说,“x && y”表示布尔“与”。在Ruby中,“x && y”也可以表示“执行x,如果结果为真,则执行y”。同样,“x || y”也可以表示“执行x,如果结果为假,则执行y”。 - joelparkerhenderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接