如何在 Ruby 循环的第一次迭代中采取不同的行动?

我总是使用一个计数器来检查循环中的第一项(i==0) :

i = 0
my_array.each do |item|
if i==0
# do something with the first item
end
# common stuff
i += 1
end

有没有一种更优雅的方法来做到这一点(也许是一种方法) ?

34223 次浏览

你可以这样做:

my_array.each_with_index do |item, index|
if index == 0
# do something with the first item
end
# common stuff
end

试试 想法频道。

数不胜数中的 each_with_index(Enumable 已经与 Array 混合在一起,因此可以对数组调用它,不会有任何问题) :

irb(main):001:0> nums = (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):003:0> nums.each_with_index do |num, idx|
irb(main):004:1* if idx == 0
irb(main):005:2> puts "At index #{idx}, the number is #{num}."
irb(main):006:2> end
irb(main):007:1> end
At index 0, the number is 1.
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

数组有一个“ each _ with _ index”方法,对于这种情况很方便:

my_array.each_with_index do |item, i|
item.do_something if i==0
#common stuff
end

Ruby 的 Enumerable#inject提供了一个参数,可用于在循环的第一次迭代中执行不同的操作:

> l=[1,2,3,4]
=> [1, 2, 3, 4]
> l.inject(0) {|sum, elem| sum+elem}
=> 10

对于像总和和乘积这样的常见事物,这种论点并不是必要的:

> l.inject {|sum, elem| sum+elem}
=> 10

但是,当您想在第一次迭代中执行某些 与众不同操作时,这个参数可能对您有用:

> puts fruits.inject("I like to eat: ") {|acc, elem| acc << elem << " "}
I like to eat: apples pears peaches plums oranges
=> nil

正如其他人所描述的那样,使用 each_with_index可以很好地工作,但是为了多样性起见,这里是另一种方法。

如果你只想为第一个元素做一些特定的事情,或者为包括第一个元素在内的所有元素做一些通用的事情,你可以这样做:

# do something with my_array[0] or my_array.first
my_array.each do |e|
# do the same general thing to all elements
end

但是如果你不想用第一个元素做一般的事情,你可以这样做:

# do something with my_array[0] or my_array.first
my_array.drop(1).each do |e|
# do the same general thing to all elements except the first
end

最适合的是根据情况而定。

另一个选项(如果你知道你的数组不是空的) :

# treat the first element (my_array.first)
my_array.each do | item |
# do the common_stuff
end

如果事后不需要数组:

ar = %w(reversed hello world)


puts ar.shift.upcase
ar.each{|item| puts item.reverse}


#=>REVERSED
#=>olleh
#=>dlrow

这里有一个解决方案,它不需要立即处于封闭循环中,并且避免了多次指定状态占位符的冗余,除非您确实需要这样做。

do_this if ($first_time_only ||= [true]).shift

它的作用域与持有者匹配: $first_time_only将全局一次; @first_time_only将实例一次,first_time_only将当前作用域一次。

如果你想要的第一个几次,等,你可以很容易地把 [1,2,3],如果你需要区分哪一个第一次迭代,甚至一些花哨的 [1, false, 3, 4],如果你需要一些奇怪的东西。