【问题标题】:Iterating over each element of an array, except the first one遍历数组的每个元素,除了第一个元素
【发布时间】:2015-04-03 01:36:45
【问题描述】:

编写此代码的惯用 Ruby 方式是什么?

给定一个数组,我想遍历该数组的每个元素,但跳过第一个。我想在不分配新数组的情况下执行此操作。

这是我想出的两种方式,但都没有感觉特别优雅。

这可行,但似乎太冗长了:

arr.each_with_index do |elem, i|
  next if i.zero? # skip the first
  ...
end

这可行,但分配了一个新数组:

arr[1..-1].each { ... }

编辑/澄清:我想避免分配第二个数组。最初我说我想避免“复制”数组,这令人困惑。

【问题讨论】:

  • 你的第二个没有复制数组。
  • @sawa 它本身并不会复制数组,但它会根据Array#[] 上的文档创建一个包含除第一个元素之外的所有元素的新数组;我误解了要求吗?
  • 我同意你的评价。另外两个选项是仅使用索引:(1...arr.size).each { |i| ....ref arr[i] ... } 或标志:first = true; arr.each { |e| if first; first = false; next; end; ... }。
  • 我编辑了问题以澄清我想避免分配新数组。这就是我写“不要复制”时的意思。
  • “复制”不是混淆术语。事实上,这是一个艺术术语。

标签: ruby arrays enumeration idioms


【解决方案1】:

使用内部枚举器当然更直观,您可以像这样相当优雅地做到这一点:

class Array
  def each_after(n)
    each_with_index do |elem, i|
      yield elem if i >= n
    end
  end
end

现在:

arr.each_after(1) do |elem|
  ...
end

【讨论】:

  • 迄今为止最好的解决方案
  • 我同意。或者,each_after 方法可以在Enumerable 上定义而不是Array 并且具有相同的效果,对吗?似乎它对非数组枚举器也很有用。
  • 非常好!根据@MattBrictson 的建议,如果没有给出块,请考虑返回一个枚举器,以允许链接。
【解决方案2】:

我想在不创建数组副本的情况下执行此操作。

1) 内部迭代器:

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

(start_index...arr.size).each do |i|
  puts arr[i]
end

--output:--
2
3

2) 外部迭代器:

arr = [1, 2, 3]
e = arr.each
e.next

loop do
  puts e.next
end

--output:--
2
3

【讨论】:

  • 谢谢!从概念上讲,这正是我的想法。即:枚举数组,丢弃第一个元素,然后处理其余元素。但是代码相当罗嗦。我想这是不可避免的?
  • 关于#2,应该注意的是,通过消除块,您扩大了以前在 OP 块中的范围。
【解决方案3】:

好的,也许这是回答我自己的问题的不好的形式。但是我一直在为此绞尽脑汁并仔细研究Enumerable 文档,我认为我找到了一个很好的解决方案:

arr.lazy.drop(1).each { ... }

这是它有效的证据:-)

>> [1,2,3].lazy.drop(1).each { |e| puts e }
2
3

简洁:是的。惯用的红宝石……也许吧?你怎么看?

【讨论】:

  • drop 仍将创建一个新数组,lazy 只会延迟此活动,直到调用 each。不错的尝试。
  • 谢谢@PinnyM。好收获!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 2020-06-10
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
相关资源
最近更新 更多