我想在数组上扩展.each
方法以实现这样的语法:
arr = ["a","b","c","d"]
arr.each do |el| puts i unless el.last? end
显然我可以这样做:
arr = ["a","b","c","d"]
arr.each_with_index do |i, index| puts i unless index+1 == arr.length end
但我喜欢将此逻辑抽象为last?
方法。
我该怎么做?
答案 0 :(得分:1)
这非常接近:
def each_with_last(arr)
arr.each_with_index do |el, index|
yield el, index + 1 == arr.length
end
end
arr = ["a","b","c","d"]
each_with_last(arr) {|el, last| puts el unless last}
正如Dave Newton指出的那样,可以向正在屈服的对象添加last?
方法而不是产生额外的布尔值,但是,正如icktoofay指出的那样,这可能会变得混乱
如果您的真实用例涉及忽略最后一个值,就像您在这里一样,在我看来这更清晰:
def all_but_last(arr)
arr.each_with_index do |el, index|
yield el unless index + 1 == arr.length
end
end
arr = ["a","b","c","d"]
all_but_last(arr) {|i| puts i}
更新:为了完整起见,我建议不要这样做:
module Enumerable
def with_last?
each_with_index do |el, index|
flag = index + 1 == count
el.define_singleton_method(:last?) {flag}
yield el
end
end
end
arr = ["a","b","c","d"]
arr.each.with_last? {|el| puts el unless el.last?}
如果arr
包含无法在其上定义单例方法的对象(如符号和Fixnums),则无效。
当然,您可以对each
本身执行此操作,以使您的示例代码按照给定的方式工作(el
/ i
错字除外),但这会使事情升级为“建议反对“真正可怕的想法”。
答案 1 :(得分:1)
扩展正在生成的对象是错误的方法,因为对象本身不应该知道它包含在给定的集合中(如果你在多个数组中有相同的对象怎么办?)
如果你想避免操作数组中的最后一项,为什么不能这样:
arr[0..-2].each {|elem| ... }
您还可以使用Darshan的第二个答案的变体扩展Enumerable,允许您排除任何给定枚举中的最后一个元素:
module Enumerable
def except_last
each_with_index do |el, index|
yield el unless index == count - 1
end
end
end
[1,2,3,4,5].each.except_last {|e| print e }
1234
(在这种情况下,each
实际上是多余的,但它在那里很好并且可读。)