我想.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?
方法。
我该怎么做?
我想.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?
方法。
我该怎么做?
扩展正在生成的对象是错误的做法,因为对象本身不应该知道它包含在给定的集合中(如果您在多个数组中有相同的对象怎么办?)
如果您只想避免对数组中的最后一项进行操作,为什么不这样做:
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
实际上是多余的,但它很好并且可读。)
这非常接近:
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
包含无法在其上定义单例方法的对象(例如 Symbols 和 Fixnums),那将不起作用。
当然,您可以对each
自己执行此操作以使您的示例代码按给定的方式工作(除了el
/i
错字),但这会将事情从“推荐反对”升级为“真正糟糕的想法”。