我如何扩展.each循环中的元素有一个最后?检查元素是否是最后一个的方法?

时间:2013-06-19 02:09:06

标签: ruby

我想在数组上扩展.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?方法。

我该怎么做?

2 个答案:

答案 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实际上是多余的,但它在那里很好并且可读。)