13

这是一个关于约定的问题。下面的两组命令返回相同的结果。

a = [1, 2, 3]

a.first  # => 1
a[0]     # => 1

a.last   # => 3
a[-1]    # => 3

在 Ruby 中哪些是首选,显式索引或函数?当然,假设这是在始终访问第一个或最后一个元素的代码中。

注意:我一直在考虑每个周期会花费的时间。因为firstlast接受参数,它们会有更多的开销,但我不知道这是否会影响社区的偏好。

谢谢!


编辑

如果你阅读了这篇文章的评论,我的最后一段就引起了激烈的争论。虽然我不记得这[x]相当于.[](x),但我的结论是正确的,即 first 和 last 有更多的开销。考虑到两者的性质,我认为这是由于first/的参数检查last。这些需要检查是否有参数,而[]可以假设它们存在。

代码

require 'benchmark'

a = [1..1000]

MAX = 1000000

Benchmark.bm(15) do |b|
  b.report("small first") { MAX.times do; a.first; end }
  b.report("small [0]")   { MAX.times do; a[0];    end }
  b.report("small last")  { MAX.times do; a.last;  end }
  b.report("small [-1]")  { MAX.times do; a[-1];   end }
end

a = [1..100000000000]

Benchmark.bm(15) do |b|
  b.report("large first") { MAX.times do; a.first; end }
  b.report("large [0]")   { MAX.times do; a[0];    end }
  b.report("large last")  { MAX.times do; a.last;  end }
  b.report("large [-1]")  { MAX.times do; a[-1];   end }
end

结果

                      user     system      total        real
small first       0.350000   0.000000   0.350000 (  0.901497)
small [0]         0.330000   0.010000   0.340000 (  0.857786)
small last        0.370000   0.000000   0.370000 (  1.054216)
small [-1]        0.370000   0.000000   0.370000 (  1.137655)
                      user     system      total        real
large first       0.340000   0.010000   0.350000 (  0.897581)
large [0]         0.320000   0.010000   0.330000 (  0.889725)
large last        0.350000   0.000000   0.350000 (  1.071135)
large [-1]        0.380000   0.000000   0.380000 (  1.119587)
4

3 回答 3

11

阅读代码比编写代码要多,而且first理解起来last花费更少的精力,尤其是对于经验不足的 Ruby 程序员或来自具有不同索引语义的语言的人。

虽然大多数程序员会立即知道这些是相同的:

a.first
a[0]

第一个仍然更容易阅读。阅读的难易程度没有显着差异,但确实存在。

last是另一个问题。访问索引 0 将使您获得几乎任何语言的数组的第一个元素。但是负索引仅在某些语言中可用。如果一个 Ruby 经验最少的 C 程序员试图阅读我的代码,他们会更快地理解哪个?:

a.last
a[-1]

负索引可能会迫使他们进行谷歌搜索。

于 2013-08-13T15:01:06.103 回答
2

由于 Matz 在其他几种语言之后设计了 Ruby,我认为这些约定来自那些其他语言。

last在 Lisp(Ruby 鼓舞人心的父母之一)中,您会使用与and方法接近的东西,first所以我会说lastandfirst是约定俗成的。

我只真正使用firstand last。我看到很多程序都使用这些方法,但最终它是你的选择。这就是 Ruby 的美妙之处;)

于 2013-08-13T14:55:18.410 回答
2

从速度的角度来看,对于较大的阵列firstlast都比[]. 对于较小的阵列,情况正好相反。

大数组:

array = (0..100000000).to_a

t = Time.now
10.times{array[0]}
puts Time.now - t
# => 0.000225356

t = Time.now
10.times{array.first}
puts Time.now - t
# => 2.9736e-05

t = Time.now
10.times{array[-1]}
puts Time.now - t
# => 7.847e-06

t = Time.now
10.times{array.last}
puts Time.now - t
# => 6.174e-06

小数组:

array = (0..100).to_a

t = Time.now
10.times{array[0]}
puts Time.now - t
# => 4.403e-06

t = Time.now
10.times{array.first}
puts Time.now - t
# => 5.933e-06

t = Time.now
10.times{array[-1]}
puts Time.now - t
# => 4.982e-06

t = Time.now
10.times{array.last}
puts Time.now - t
# => 5.411e-06

为了便于书写/阅读,first并且last可以不带参数使用,不像[],所以它们更简单。

有时,使用firstandlast让事情变得更容易,而[]使用array.each_slice(3).map(&:first).

于 2013-08-13T15:16:09.647 回答