【问题标题】:Why does each_cons yield arrays instead of multiple values?为什么 each_cons 产生数组而不是多个值?
【发布时间】:2016-10-06 23:39:06
【问题描述】:

我只是想对数组中的连续元素应用二元运算,例如:

[1, 2, 3, 4].each_cons(2).map { |a, b| a.quo(b) }
#=> [(1/2), (2/3), (3/4)]

这是一个人为的例子,操作并不重要。

我很惊讶,我不能只写:

[1, 2, 3, 4].each_cons(2).map(&:quo)
#=> NoMethodError: undefined method `quo' for [1, 2]:Array

这是因为each_cons 不会产生多个值,而是一个包含这些值的数组。

它是这样工作的:

def each_cons_arrays
  return enum_for(__method__) unless block_given?
  yield [1, 2]
  yield [2, 3]
  yield [3, 4]
end

each_cons_arrays.map(&:quo)
#=> NoMethodError: undefined method `quo' for [1, 2]:Array

我希望:

def each_cons_values
  return enum_for(__method__) unless block_given?
  yield 1, 2
  yield 2, 3
  yield 3, 4
end

each_cons_values.map(&:quo)
#=> [(1/2), (2/3), (3/4)]

这背后的原因是什么?为什么总是有一个数组会更好?

顺便说一句,另一方面,with_index 确实会产生多个值:

[1, 1, 1].each.with_index(2).map(&:quo)
#=> [(1/2), (1/3), (1/4)]

【问题讨论】:

  • 如果你在做 each_cons(3) 会有什么期望?你问的可能只适合each_cons(2)
  • @WandMaker 它产生 3 个值。当然,这不适用于 quo,因为它只需要 1 个参数。
  • 此外,我认为each_cons(2) 是一个非常常见的情况。
  • 我不是这个意思。 With_index、with_object 总是产生 2 个值,而 each_cons 产生一个变化的数字。对于较小的 n 值,each_cons(n) 为您的用例产生值可能会很好,但对于较大的 n 值或使用数组会更好
  • @sawa 我现在已经提交了bug report,但我不太确定这是否真的是一个错误。

标签: arrays ruby enumerator


【解决方案1】:

根据我的经验,将 ruby​​ 中的多个值视为一个数组会有所帮助。

它认为它是

[1,2,3].each_cons(2) do |iter|
  a,b = iter
  do_stuff(a,b)
end

如果你想这样做,我会将quo 方法添加到自定义类中,然后

class Foobar
  def initialize(a,b)
    @a = a
    @b = b
  end

  def quo
    do_stuff
  end
end

[1,2,3]
  .each_cons(2)
  .map { |a,b| Foobar.new(a,b) }
  .map(:quo)

这对您的用例有用吗?

【讨论】:

  • 你的第一个例子只能这样工作,因为each_cons 产生数组。但是产生多个值和产生一个包含这些值的数组是有区别的。例如,each_with_index确实产生多个值,因此,%w(a b c).each_with_index.map { |e| e } 返回["a", "b", "c"],而不是[["a", 0], ["b", 1], ["c", 2]]