我正在使用Ruby on Rails 3.0.7,我想迭代一个对象数组(类istances),除了id
等于1
的元素({{1} }引用数组[id
]索引)。
我知道我可以在1
语句“内部”使用if
语句并执行此操作,检查每个“当前”\“已考虑”元素each
。但是,由于数组中包含大量数据,我想找到另一种方法,以更高效的方式完成相同的事情(避免每次都运行if id == 1
。)
我该怎么办?
答案 0 :(得分:7)
我们应该忘记小事 效率,约占97% 时间:过早优化是 万恶之源。
现在,您可以执行以下操作:
def f
do_something
end
f 0
for i in 2..n
f i
end
甚至:
def f
yield 0
for i in 2..@n
yield i
end
end
f do |i|
do_something
end
但你可能不希望想要做任何类似的事情,如果你这样做了,那只会在发现重要之后才会发生。
最后,假设这个丑陋的技巧实际上让你的服务器运行得如此之快。值得吗?
答案 1 :(得分:1)
if
声明是一种非常便宜的操作。您可以使用标准基准测试工具进行检查。
require "benchmark"
array = [1] * 100_000
Benchmark.bm do |bm|
bm.report "with if" do
array.each_with_index do |element, i|
next if i == 1
element - 1
end
end
bm.report "without if" do
array.each do |element|
element - 1
end
end
end
结果:
user system total real
with if 0.020000 0.000000 0.020000 ( 0.018115)
without if 0.010000 0.000000 0.010000 ( 0.012248)
在100 000个元素阵列上差异大约为0.006秒。你不应该关心它,除非它成为一个瓶颈,我怀疑它会。
答案 2 :(得分:1)
a = ['a', 'b', 'c']
a.each_with_index.reject {|el,i| i == 1}.each do |el,i|
# do whatever with the element
puts el
end
恕我直言是一种更好的选择方式,而不是使用您自己的显式if
语句。不过,我相信它会产生与使用if
大致相同的性能,甚至可能会略低一些。
如果在基准测试之后,其他人已经建议您知道这个时间肯定比您允许的时间慢,并且选择导致缓慢,那么这可以很容易地修改以通过多种方式删除选择:
a = ['a', 'b', 'c']
n = 1
(a.first(n) + a.drop(n + 1)).each do |el|
# do whatever with the element
puts el
end
不幸的是我相信这也会比运行简单的if慢。我认为可能具有速度潜力的是:</ p>
a = ['a', 'b', 'c']
n = 1
((0...n).to_a+((n+1)...a.size).to_a).map{|i| a[i]}.each do |el|
# do whatever with the element
puts el
end
但这又有可能变慢。
修改强>
基准为this gist。这些结果实际上让我感到惊讶,拒绝是迄今为止最慢的选择,其次是范围。完全没有删除元素后效果最高的是使用first
和drop
来选择它周围的所有元素。
结果为百分比,不使用选择作为基线:
with if 146%
with first and drop 104%
without if 100%
显然,这高度依赖于你对元素的处理,这可能是Ruby可以执行的最快的操作。操作越慢,这些差异越小。一如既往:基准,基准,基准
答案 3 :(得分:1)
测试一个实际的for循环可能值五分钟。它可能在Ruby圈子中不受欢迎,但这并不意味着它永远不值得使用。当你调用每个或map或者其他什么时,这些方法都会以任何方式使用for循环。避免绝对。
它还取决于阵列可以达到多大,在某些n,一个可能变得比另一个快。在这种情况下,绝对不值得。
如果您不需要特定元素,则可能不需要将该行数据存储在数据库中。第1行和其他行之间有什么区别,换句话说,为什么要跳过它? id = 1的行总是会有相同的数据吗?如果是这样,将其存储为常数可能会更好,并会使您的问题没有实际意义。性能几乎总是会花费更多的内存。
除非Rails 3以不同的方式执行操作,并且您提取数据并使用id作为查找程序键,否则id = 1将位于元素0中。
不幸的是,Knuth的引用经常被误解,并习惯于为程序员受过足够教育而无法编写的糟糕,效率低下的代码提供借口,并考虑了5秒钟。当然,花一个星期试图加速你不知道的代码是一个问题或是一个小问题,但这更像是Knuth所说的。表演是计算机科学中最容易被误解和滥用的概念之一。