我有一个产生对象的方法foo
。我想计算它产生的对象数量。
我有
def total_foo
count = 0
foo { |f| count += 1}
count
end
但可能有更好的方法。对这个新Rubyist的任何想法?
这是foo
的定义(它是Rails中的辅助方法):
def foo(resource=@resource)
resource.thingies.each do |thingy|
bar(thingy) { |b| yield b } # bar also yields objects
end
end
答案 0 :(得分:3)
任何调用yield
的方法都可用于构建Enumerator
对象,您可以通过count
方法调用Object#to_enum
。请记住,当您调用count
时,迭代器实际上已执行,因此它应该没有副作用!遵循模仿您的场景的可运行示例:
@resources = [[1,2], [3,4]]
def foo(resources = @resources)
resources.each do |thingy|
thingy.each { |b| yield b }
end
end
foo { |i| puts i }
# Output:
# 1
# 2
# 3
# 4
to_enum(:foo).count
# => 4
您可以将参数传递给foo
:
to_enum(:foo, [[5,6]]).count
# => 2
或者,您可以定义foo
以在没有块的情况下调用Enumerator
,这是stdlib迭代器的工作方式:
def foo(resources = @resources)
return to_enum(__method__, resources) unless block_given?
resources.each do |thingy|
thingy.each { |b| yield b }
end
end
foo.count
# => 4
foo([[1,2]]).count
# => 2
foo([[1,2]]) { |i| puts i }
# Output:
# 1
# 2
当您在to_enum
上致电size
以返回值时,您可以将阻止传递给Enumerator
:
def foo(resources = @resources)
unless block_given?
return to_enum(__method__, resources) do
resources.map(&:size).reduce(:+) # thanks to @Ajedi32
end
end
resources.each do |thingy|
thingy.each { |b| yield b }
end
end
foo.size
# => 4
foo([]).size
# => 0
在这种情况下,使用size
比count
快一点,您的里程可能会有所不同。
答案 1 :(得分:1)
假设您只关心foo
的副作用,您可以让foo
自己计算迭代次数:
def foo(resource=@resource)
count = 0
resource.thingies.each do |thingy|
bar(thingy) do |b|
count += 1
yield b
end # bar also yields objects
end
count
end
然后:
count = foo { |f| whatever... }
如果您选择,您也可以忽略返回值,所以只需:
foo { |f| whatever... }
如果你不在乎计数是什么。
根据更大的背景,可能有更好的方法来处理所有这些。