Ruby/Rails 循环中神奇的第一个和最后一个指示器?
当涉及到基本事物的糖时,Ruby/Rails 做了很多很酷的事情,我认为有一个非常常见的场景,我想知道是否有人做过助手或类似的东西。
a = Array.new(5, 1)
a.each_with_index do |x, i|
if i == 0
print x+1
elsif i == (a.length - 1)
print x*10
else
print x
end
end
请原谅丑陋,但这达到了人们可能想要的...是否有一种红宝石方式可以对循环的第一个和最后一个执行某些操作?
[编辑] 我认为理想情况下,这将是带有参数的数组扩展(数组实例、所有元素函数、第一个元素函数、最后一个元素函数)...但我对其他想法持开放态度。
Ruby/Rails does lots of cool stuff when it comes to sugar for basic things, and I think there's a very common scenario that I was wondering if anyone has done a helper or something similar for.
a = Array.new(5, 1)
a.each_with_index do |x, i|
if i == 0
print x+1
elsif i == (a.length - 1)
print x*10
else
print x
end
end
Pardon the ugliness, but this gets at what one might want... is there a ruby way to do something to the first and last of a loop?
[EDIT] I think ideally this would be an extension on Array with parameters (array instance, all elements function, first elements function, last elements function)... but I'm open to other thoughts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
如果您愿意,您可以抓取第一个和最后一个元素并以不同的方式处理它们。
You could grab the first and last elements and process them differently, if you like.
如果第一次和最后一次迭代的代码与其他迭代的代码没有任何共同点,您也可以这样做:
如果不同的情况有一些共同的代码,那么您的方法就可以了。
If the code for the first and last iteration has nothing in common with the code for the other iterations, you could also do:
If the different cases have some code in common, your way is fine.
如果你能做到这一点呢?
还是这个?
在 MRI >= 1.8.7 中,所需要的只是这个猴子补丁:
它有一个小状态引擎,因为它必须向前看一次迭代。
诀窍是each,each_with_index,&c。如果没有给定块,则返回一个枚举器。枚举器可以完成枚举器所做的所有事情,甚至更多。但对我们来说,重要的是我们可以对 Enumerator 进行猴子修补,以添加另一种迭代方式,“包装”现有迭代,无论它是什么。
What if you could do this?
Or this?
In MRI >= 1.8.7, all it takes is this monkey-patch:
It's got a little state engine because it must look ahead one iteration.
The trick is that each, each_with_index, &c. return an Enumerator if given no block. Enumerators do everything an Enumerable does and a bit more. But for us, the important thing is that we can monkey-patch Enumerator to add one more way to iterate, "wrapping" the existing iteration, whatever it is.
或者一个很小的领域特定语言:
以及让它运行的代码:
我开始思考,“如果您可以将多个块传递给 Ruby 函数,那么您就可以对这个问题有一个巧妙而简单的解决方案。”然后我意识到 DSL 的一些小技巧几乎就像传递多个块一样。
Or a tiny little Domain Specific Language:
and the code that makes it go:
I started thinking, "if only you could pass multiple blocks to a Ruby function, then you could have a slick and easy solution to this question." Then I realized that DSL's play little tricks that are almost like passing multiple blocks.
正如许多人指出的那样,each_with_index 似乎是关键。我有我喜欢的这个代码块。
Or
或 通过数组扩展
As many have pointed out,
each_with_index
seems to be the key to this. I have this code block that I liked.Or
Or by Array extensions
如果您愿意添加一些样板文件,您可以将类似的内容添加到数组类中:
然后在任何需要的地方,您将获得以下语法:
对于以下输出:
If you are willing to add some boilerplate, you can add something like this to the array class:
and then anywhere you need to, you get the following syntax:
for the following output:
Ruby 中没有“(第一次|最后一次)执行此操作”语法。但如果您正在寻找简洁性,您可以这样做:
结果就是您所期望的:
There's no "do this the (first|last) time" syntax in Ruby. But if you're looking for succinctness, you could do this:
The result is what you'd expect:
有趣的问题,我也思考过。
我认为您必须创建三个不同的块/过程/无论它们被称为什么,然后创建一个调用正确的块/过程/无论什么的方法。 (抱歉含糊不清 - 我还不是黑带元程序员)[编辑:但是,我是从底层的人那里复制的)
产生
编辑: Svante 对相关问题的答案(以及molf的建议)问题显示如何将多个代码块传递给单个方法:
Interesting question, and one I've thought a bit about as well.
I think you'd have to create three different blocks/procs/whatever they're called, and then create a method that calls the correct block/proc/whatever. (Sorry for the vagueness - I'm not yet a black belt metaprogrammer) [Edit: however, I've copied from someone who is at the bottom)
produces
Edit: Svante's answer (with molf's suggestion) to a related question shows how to pass in multiple code blocks to a single method:
我时不时地需要这个功能,所以我为此目的制作了一个小类。
最新版本位于: https://gist.github.com/3823837
示例:
实际课程:
I needed this functionality from time to time, so I crafted a little class for that purpose.
The latest version is at: https://gist.github.com/3823837
Sample:
Actual class:
吻
KISS
我无法抗拒:)这并没有针对性能进行调整,尽管我想它应该不会比这里的大多数其他答案慢很多。都是糖惹的祸!
示例 1:
示例 2:
I could not resist :) This is not tuned for performance although i guess it is should not be much slower than most of the other answers here. It's all about the sugar!
Example 1:
Example 2:
如果您不介意“最后”操作发生在中间的内容之前,那么这个猴子补丁:
允许这样做:
If you don't mind that the "last" action happens before the stuff in the middle, then this monkey-patch:
Allows this:
将数组划分为多个范围,每个范围内的元素应该表现不同。将由此创建的每个范围映射到一个块。
可以手动创建范围,但下面的这些帮助器使它更容易:
用法:
Partition the array into ranges where elements within each range are supposed to behave different. Map each range thus created to a block.
Could create ranges by hand, but these helpers below make it easier:
Usage:
我在这里看到很多非常接近的黑客,但都严重依赖于给定的具有固定大小的迭代器而不是迭代器。我还想建议在迭代时保存前一个元素,以了解迭代的第一个/最后一个元素。
I see a lot of hacks here that are pretty close, but all heavily dependent on the given iterator having a fixed size and NOT being an iterator. I'd like to also propose saving the previous element as you iterate through to know the first/last element that was iterated over.
如果您知道数组中的项目是唯一的(与本例不同),您可以这样做:
If you know the items in the array are unique (unlike this case), you can do this:
有时 for 循环只是你最好的选择
我知道这个问题已得到解答,但这种方法没有副作用,并且不会检查第 13、14、15.. 第 10thousandth、10,001... 记录是否是第一条记录,或最后一个。
以前的答案在任何数据结构类中都会失败。
Sometimes a for loop is just your best option
I know this question was answered, but this method has no side effects, and doesn't check if the 13th, 14th, 15th.. 10thousandth, 10,001th... record is the first record, or the last.
Previous answers would have failed the assignment in any data structures class.