The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Benchmarking: Sorting Arrays in Descending Order

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Florian Frank

Posts: 48
Nickname: ffrank
Registered: Dec, 2005

Florian Frank is a humanoid life-form, living on the third planet of the solar system.
Benchmarking: Sorting Arrays in Descending Order Posted: May 29, 2007 9:53 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Florian Frank.
Original Post: Benchmarking: Sorting Arrays in Descending Order
Feed Title: The Rubylution: Tag Ruby
Feed URL: http://rubylution.ping.de/xml/rss/tag/ruby/feed.xml
Feed Description: Starts… Now.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Florian Frank
Latest Posts From The Rubylution: Tag Ruby

Advertisement

Recently i wanted to sort an array of array pairs (array.size == 2) in descending (highest value first) order in Ruby. I wanted to avoid creating a temporary array for this, so at first I used Array#sort with a block.

Because the sorting would often be called in my algorithm, I wanted to optimize this part of the code a bit. I started to benchmark in order to verify, that my assumptions are correct.

This is the setup data for the benchmarks:

n   = 1000
a   = Array.new(n) { [ rand(1000), rand(1000) ] }
a2  = Array.new(n) { rand(1000) }
m   = 1000

array sizes are n, a is my array of pairs, a2 is for comparison only, and I repeat the benchmarked code m-times. (I also do a full warmup run before that.)

This was my first stab at the sorting (I don't care about the first value in the pair, BTW):

a.sort { |x, y| y <=> x } # => " 11.62s 0.011618c/s"

This took quite some time. (The first time value is the duration in seconds, the second the calls per second.) I guessed that calling the block ca. n log(n) times, was the reason for this, so I tried:

b = a.sort; b.reverse! # => "  3.29s 0.003290c/s"

Wow! Much better. This takes ca. k n log(n) + l n "machine instructions", while l << k, so the reverting doesn't matter neither in theory or praxis. This can be shown, by just benchmarking Array#sort:

a.sort # => "  3.48s 0.003484c/s"

This has essentially the same speed as the benchmark with reverse. Actually it's slower, which means, that I cannot even measure Array#reverse's speed in this benchmark.

So let's test a2 to find out, how fast comparing Fixnums is compared to the more complex pair Arrays:

a2.sort # => "  0.27s 0.000265c/s"

That's quite a speedup, so let's try to profit from that:

a.sort { |x, y| y.last <=> x.last } # => " 13.97s 0.013968c/s"

Hmm, this didn't work out. But why? I remembered that Ruby's sort cheats a bit for immediate values like Fixnum, that's most likely the reason. (But I am to lazy to look it up just now.) Making the sort block more complex than in the first try didn't help either.

But what can be gained from these examples is that

  1. using a complex compare block, leads to a huge slowdown in sorting time and
  2. comparing more primitive values can be much faster (especially if all of this happens in C).

This convinced me to try Array#sort_by, which I dismissed from the beginning as being too wasteful of memory (and maybe too slow because of this anyway):

a.sort_by { |x| -x.last } # => "  2.77s 0.002766c/s"

LOL! I really should stop making predictions without benchmarking: I almost always guess wrong, if I do it. This is the fastest way to sort a in descending OR ascending order. Because it combines Ruby's cheating with Fixnums (-x.last) and only calling the { |x| -x.last }-block n-times instead of calling the more complex one ca. n * log(n) times.

On the other hand it's only a good idea to invest much time into figuring out and exploiting implementation details like this, if you need the speed, need it now and on this Ruby implementation. The used implementation could change in the future or the advantages could turn into drawbacks if you run the algorithm on JRuby for example.

P.S.: Benchmark code can be downloaded.

Read: Benchmarking: Sorting Arrays in Descending Order

Topic: Testing: Replace Collaborator with Stub Previous Topic   Next Topic Topic: Testing: Refactoring Examples

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use