42

代码:

 c = 0  
 items.each { |i|  
   puts i.to_s    
   # if c > 9 escape the each iteration early - and do not repeat  
   c++  
 }  

我想抓住前 10 个项目,然后离开“每个”循环。

我用什么替换注释行?有更好的方法吗?更多 Ruby 惯用的东西?

4

8 回答 8

61

While the break solution works, I think a more functional approach really suits this problem. You want to take the first 10 elements and print them so try

items.take(10).each { |i| puts i.to_s }
于 2009-10-14T19:26:42.713 回答
51

Ruby中没有++运算符。对于多行块,使用do和也是惯例。end修改您的解决方案会产生:

c = 0  
items.each do |i|  
  puts i.to_s    
  break if c > 9
  c += 1 
end

或者还有:

items.each_with_index do |i, c|  
  puts i.to_s    
  break if c > 9
end

另请参阅each_with_indexProgramming Ruby Break、Redo 和 Next

更新: Chuck 对范围的回答更像 Ruby,nimrodm 的回答使用take更好。

于 2009-10-14T19:04:59.067 回答
7

break works for escaping early from a loop, but it's more idiomatic just to do items[0..9].each {|i| puts i}. (And if all you're doing is literally printing the items with no changes at all, you can just do puts items[0..9].)

于 2009-10-14T19:24:50.540 回答
4

Another variant:

puts items.first(10)

Note that this works fine with arrays of less than 10 items:

>> nums = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> puts nums.first(10)
1
2
3
4
5

(One other note, a lot of people are offering some form of puts i.to_s, but in such a case, isn't .to_s redundant? puts will automatically call .to_s on a non-string to print it out, I thought. You would only need .to_s if you wanted to say puts 'A' + i.to_s or the like.)

于 2009-10-14T19:34:46.910 回答
4

Another option would be

items.first(10).each do |i|
  puts i.to_s
end

That reads a little more easily to me than breaking on an iterator, and first will return only as many items as available if there aren't enough.

于 2009-10-14T19:36:32.383 回答
1

这看起来像你想要的吗?

10.times { |i|
  puts items[i].to_s
}
于 2009-10-14T19:02:36.017 回答
0
items.each_with_index { |i, c| puts i and break if c <= 9 }
于 2009-10-14T19:15:15.087 回答
-1

有人问:

我想抓住前 10 个项目,然后离开“每个”循环。

使用throwandcatch来完成此操作,只需对示例进行少量更改:

catch(:done) do
    c = 0
    collected = []
    items.each do |item|
        collected << item
        throw(:done, collected) if c == 9 # started at 0
        c += 1
    end
    collected # if the list is less than 10 long, return what was collected
end

只需带有和which is waiting forthrow的标签就会返回。:donecollectedcatch:donecollected

并把它“红宝石”一下:

catch(:done) do
    items.inject([]) do |collected, item|
        throw(:done, collected) if collected.size == 10
        collected << item # collected gets returned here and populates the first argument of this block
    end
end

我不知道为什么有些人拒绝使用inject和使用reduce(它们是等效的),而显然给定的空数组inject([])正在被注入items! 无论如何,如果少于 10 个项目inject将返回。collected

大多数答案都试图回答问题的意图,而不是被问到的内容,并且items.take(10)在这种情况下确实很有意义。但我可以想象想要抢购符合我 100 美元预算的第一批物品。然后你可以简单地:

catch(:done) do
    items.inject({items: [], budget: 100}) do |ledger, item|
        remainder = ledger[:budget] - item.price
        if remainder < 0
            throw(:done, ledger)
        else
            ledger.tap do |this|
                this[:items] << item
                this[:budget] = remainder
            end # tap just returns what is being tapped into, in this case, ledger
        end
    end
end
于 2017-01-21T14:18:46.123 回答