From: Robert Klemme Date: 2010-10-06T17:14:17+09:00 Subject: Re: Sorting problem with an Array of Arrays On Thu, Sep 23, 2010 at 10:45 PM, (r.*n){2} wrote: > On Sep 23, 11:27 am, Jeremy Bopp wrote: >> On 9/22/2010 11:30 PM, Paul wrote: >> >> > Hi Jeremy, thanks for the reply. >> >> > On Sep 22, 6:54 pm, Jeremy Bopp wrote: >> >> >>> You could define a class to represent each of your inner array elements. >> >>>  That class could then define the <=> method in which you could compare >> >>> each item in the order you desire.  Then your outer array, consisting of >> >>> instances of your class, could be trivially sorted with Array#sort. >> >> > I'm afraid I don't understand what you are saying here.  All I >> > understood was "could be trivially sorted with Array#sort."  I don't >> > understand classes. >> >> Classes are rather a central concept in Ruby, so it would be a really >> good idea to learn about them; however, they are not necessary here. >> I'll keep this short and say that using an array of arrays such as what >> you have here can make your code cryptic and brittle as it grows and >> ages.  Using a class to represent your inner array items will help avoid >> these issues. :-) >> >> I see that you have more details about your problem in a later reply, so >> I'll see about addressing more issues there. >> >> -Jeremy > > $cat h1.rb > #!/usr/bin/ruby > puts [ >  ["DEF-1", 1271772000, 1], >  ["ABC-2", 1271773800, 1], >  ["ABC-3", 1271863200, 2], >  ["AAA-1", 1271862000, 2], >  ["ABC-4", 1271869200, 2], >  ["ABC-1", 1271768400, 2] > ].sort{ |x,y| (x[1] <=> y[1]) * 10 + (x[0] <=> y[0]) }.inspect The approach with multiplying is fragile. I would prefer one of these approaches: 10:03:18 tmp$ cat x.rb require 'pp' data = [ ["DEF-1", 1271772000, 1], ["ABC-2", 1271773800, 1], ["ABC-3", 1271863200, 2], ["AAA-1", 1271862000, 2], ["ABC-4", 1271869200, 2], ["ABC-1", 1271768400, 2] ] pp data.sort_by {|x| [x[1], x[0]]} pp data.sort do |(la,ta,na),(lb,tb,nb)| c = ta <=> tb c == 0 ? la <=> lb : c end 10:03:24 tmp$ ruby19 x.rb [["ABC-1", 1271768400, 2], ["DEF-1", 1271772000, 1], ["ABC-2", 1271773800, 1], ["AAA-1", 1271862000, 2], ["ABC-3", 1271863200, 2], ["ABC-4", 1271869200, 2]] [["AAA-1", 1271862000, 2], ["ABC-1", 1271768400, 2], ["ABC-2", 1271773800, 1], ["ABC-3", 1271863200, 2], ["ABC-4", 1271869200, 2], ["DEF-1", 1271772000, 1]] 10:03:26 tmp$ However, as Jeremy said already, using specific classes is much more preferable because it makes the code easier to read and less error prone. In this case it can be as simple as 10:13:34 tmp$ cat y.rb require 'pp' Booking = Struct.new :label, :timestamp, :room do include Comparable # defines default ordering: # 1. timestamp # 2. label def <=> o c = timestamp <=> o.timestamp c == 0 ? label <=> o.label : c end end data = [ Booking["DEF-1", 1271772000, 1], Booking["ABC-2", 1271773800, 1], Booking["ABC-3", 1271863200, 2], Booking["AAA-1", 1271862000, 2], Booking["ABC-4", 1271869200, 2], Booking["ABC-1", 1271768400, 2] ] pp data.sort 10:13:37 tmp$ ruby19 y.rb [#, #, #, #, #, #] 10:13:41 tmp$ Btw, I'd also use Time instances for the timestamps but class Booking also works with Fixnums which you have in your data. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/