2

If array = [1, 2, 3], then theoretically speaking, is there a difference in speed between calling array[-1] and array[2]?

(And in general terms, for any array where array.length == n, is there a difference between calling array[-1] and array[n-1]?)

6

2 Answers 2

7

I am not an expert, so benchmarked to test which one is faster,

require 'benchmark'
require 'bigdecimal/math'

array = (1..10000).to_a

puts Benchmark.measure { puts array[-1] }
#=> 0.000030

puts Benchmark.measure { puts array[10000-1] }
#=> 0.000031

I think the difference is negligible.

Sign up to request clarification or add additional context in comments.

5 Comments

Note: This uber-micro benchmark does not imply a[-1] is "faster" or even that there is a measurable difference, but it does indicate that "it doesn't matter".
@user2864740, yes it doesn't matter.
Putting puts inside the block distorts the results, and performing a single calculation for each is not sufficient. I changed your benchmarks to { 1_000_000.times { a = array[-1] } } and { 1_000_000.times { a = array[10000-1] } } , did 10 runs and found found that the first was faster by an average of 10.5%, but the percentages by with the first was faster varied quite a bit, as shown in the following (sorted, with values rounded) array: [45, 37, 8, 5, 4, 4, 3, 2, 0, -2].
It's worth noting that getting n might be the slow part here, so array[array.length-1] vs. array[-1] is a more fair comparison.
@tadman, I reran the benchmarks with { 1_000_000.times { array[-1] } } and { 1_000_000.times { array[10000-1] } }. This time the first was on average 4.3% faster. The percentage differences were as follows: [25, 13, 6, 5, 5, 2, 2, 1, -2, -13]. Eliminating the assignment a = reduced solution times by about 5% (only). The two sets of results don't seem consistent, but I expect that's due to my relatively small sample size (of 10).
1

We should measure! I'm going to hypothesize that [-1] and #last will be slightly faster than [len - 1] due to having one less method call.

require 'benchmark/ips'

arr = (1..100).to_a

Benchmark.ips do |x|
  x.report("last") { arr.last }
  x.report("-1") { arr[-1] }
  x.report("len - 1") { arr[arr.length - 1] }
end

Results:

$ ruby -v
ruby 2.0.0p353 (2013-11-22 revision 43784) [x86_64-linux]
$ ruby bench.rb

Calculating -------------------------------------
                last    127496 i/100ms
                  -1    133726 i/100ms
             len - 1    127050 i/100ms
-------------------------------------------------
                last  6528395.1 (±0.4%) i/s -   32638976 in   4.999622s
                  -1  7802109.3 (±1.7%) i/s -   39047992 in   5.006745s
             len - 1  7046531.5 (±0.3%) i/s -   35319900 in   5.012415s

$ ruby -v
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]
$ ruby bench.rb

Calculating -------------------------------------
                last    130228 i/100ms
                  -1    129587 i/100ms
             len - 1    126966 i/100ms
-------------------------------------------------
                last  6787424.0 (±0.2%) i/s -   33989508 in   5.007732s
                  -1  7915058.4 (±0.6%) i/s -   39653622 in   5.010079s
             len - 1  7126295.0 (±0.5%) i/s -   35677446 in   5.006563s


$ ruby -v
jruby 1.7.18 (1.9.3p551) 2014-12-22 625381c on
  OpenJDK 64-Bit Server VM 1.8.0_25-b18 +jit [linux-amd64]
$ ruby bench.rb

Calculating -------------------------------------
                last   212.085k i/100ms
                  -1   226.292k i/100ms
             len - 1   226.245k i/100ms
-------------------------------------------------
                last     13.935M (± 4.4%) i/s -     69.352M
                  -1     13.696M (± 5.1%) i/s -     68.340M
             len - 1     11.732M (± 3.2%) i/s -     58.597M

-1 is very slightly faster under ruby 2.0.0 and 2.1.1, #last is fastest under JRuby (which is itself almost 2x faster than MRI, probably because of that delicious JIT).

In all cases, it runs really fast and it's probably one of the last things you should be trying to optimize.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.