2015-04-03 92 views
3

什么是写这段代码的惯用Ruby方式?迭代数组中的每个元素(第一个元素除外)

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

以下是我提出的两种方法,但都不觉得特别优雅。

这工作,但似乎太冗长:

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

这工作,但分配一个新的数组:

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

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

+1

你的第二个不会使数组的副本。 – sawa 2015-04-03 01:38:09

+2

@sawa它不会复制数组本身,但它会创建一个新的数组,除了第一个元素外,每个'Array#[]'上的文档都会被创建。我误解了这个要求吗? – 2015-04-03 02:41:21

+0

我同意你的评估。其他两个选项仅使用索引:'(1 ... arr.size).each {| i | .... ref arr [i] ...}'或一个标志:'first = true; arr.each {| e |如果第一个; first = false;下一个;结束; ''。 – 2015-04-03 03:05:57

回答

5

使用内部枚举肯定是更直观,你可以做到这一点相当优雅,像这样:

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 
+0

迄今为止最好的解决方案 – 2015-04-03 04:53:34

+0

我同意。或者,'each_after'方法可以在'Enumerable'而不是'Array'上定义,并且具有相同的效果,对吧?似乎它对于非数组枚举器也很有用。 – 2015-04-03 04:56:55

+0

非常好!还有@ MattBrictson的建议,如果没有给出块,考虑返回一个枚举器,以允许链接。 – 2015-04-03 08:29:26

1

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

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 
+0

谢谢!从概念上讲,这正是我想到的。即:枚举数组,放弃第一个元素,然后处理其余的元素。但代码很罗嗦。我想这是不可避免的? – 2015-04-03 03:33:25

+0

关于#2,应该注意的是,通过消除块,你已经扩大了以前在OP的块中的范围。 – 2015-04-03 03:44:56

0

好吧,也许这是不好的形式来回答我的问题。但我已经费尽我对这个大脑和钻研的Enumerable文档,我想我已经找到了一个很好的解决方案:

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

这里的证明,它的作品:-)

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

简洁:是的。习语Ruby ......也许?你怎么看?

+2

'drop'仍然会创建一个新的数组,'lazy'只会延迟这个活动,直到调用'each'。不错,尽管。 – PinnyM 2015-04-03 04:34:52

+0

谢谢@PinnyM。接得好! – 2015-04-03 04:37:41

相关问题