代码:
c = 0
items.each { |i|
puts i.to_s
# if c > 9 escape the each iteration early - and do not repeat
c++
}
我想抓取前10个项目,然后离开"each"循环。我应该用什么替换注释行?有没有更好的方法?更符合Ruby惯用语法的方法?
代码:
c = 0
items.each { |i|
puts i.to_s
# if c > 9 escape the each iteration early - and do not repeat
c++
}
我想抓取前10个项目,然后离开"each"循环。虽然 break
方案可行,但我认为一种更加功能化的方法更适合这个问题。你想要取出
前十个元素并打印它们,所以尝试使用
items.take(10).each { |i| puts i.to_s }
puts items.take(10)
- Telemachustake
模块的参考资料。它在API中的哪个模块里? - Sarah Vessels关于Array#take什么也不知道
。 - Chris LutzArray#take
存在于 Ruby 1.8.7 及以上版本。 - ChuckRuby 中没有 ++
运算符。另外,惯例是在多行代码块中使用 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_index
以及Programming Ruby Break, Redo, and Next。
更新:使用范围的Chuck的答案更符合Ruby的习惯,而使用take
的nimrodm的答案则更好。
++
。花括号用于块是可以的,只是对于多行块不是首选;请参见 https://dev59.com/enRB5IYBdhLWcg3wuZfo - Sarah Vesselsbreak
可以用来提前退出循环,但更加惯用的方法是使用 items[0..9].each {|i| puts i}
。(如果你只是简单地打印项目而没有做任何修改,可以直接使用 puts items[0..9]
。)
puts items[0..9].join("\n")
。 - Bob Aman另一种变体:
puts items.first(10)
>> nums = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> puts nums.first(10)
1
2
3
4
5
puts i.to_s
的形式,但在这种情况下,.to_s
是否有些多余呢?我认为puts
会自动调用非字符串类型的.to_s
来打印输出。只有当您想要说puts 'A' + i.to_s
或类似内容时,才需要使用.to_s
。)items.first(10).each do |i|
puts i.to_s
end
对我来说,这比在迭代器上中断要容易理解得多,如果没有足够的项,"first"仅返回可用项数。
这看起来像是你想要的吗?
10.times { |i|
puts items[i].to_s
}
break if items[i] == nil
пЉМдљЖж≠§жЧґзЬЛиµЈжЭ•еЇФиѓ•дљњзФ®each_with_index
гАВ - Chris Lutzitems.each_with_index { |i, c| puts i and break if c <= 9 }
and
的惰性求值吗?它可以工作,但对我来说有点太聪明了。因为我看到“and break if”在一起,我的大脑一直想着使用>=
。 - Telemachusputs
工作时,它返回nil
。因此,只要索引等于或小于9,就会发生puts
,返回nil
并且不会评估and
的第二个部分。当索引达到10时,puts
不会发生,and
的第二个部分被评估。此时,出现问题:break
。 - Telemachusif c <= 9; puts i; break; end
。 and break
永远不会被执行,因为 puts i
总是返回 nil,一旦 c>9,整个 if 语句块就不再执行。如果想证明这个分支永远不会到达,请将 break
替换为 (puts "YOU WON'T SEE THIS")
。 - Chuckthrow
和catch
来完成这个任务,对示例进行少量更改: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
只需使用throw
指令并带上标签:done
和collected
参数,等待:done
标签的catch
指令将返回collected
参数。
如果要使用Ruby语言实现:
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([])
中传入了item
时,空数组被注入!总之,如果少于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
throw
和 catch
,也不需要将其转化为13行深度嵌套的代码。保持简单。 - NeuroXc