From: Josh Cheek Date: 2009-08-31T03:58:26+09:00 Subject: Re: Sorting an array by multiple elements? --000e0cd241c65a11a30472606d6e Content-Type: text/plain; charset=ISO-8859-1 On Sun, Aug 30, 2009 at 12:25 PM, Paul Carvalho wrote: > On Aug 30, 11:41 am, "David A. Black" wrote: > > > > The nothing result seems strange. This: > [snip] > > > > data = [ [2, "2009-08-21", 2, "alfie"], > > [6, "2009-08-23", 3, "alfie"], > > [1, "2009-08-21", 4, "barny"], > > [3, "2009-08-23", 3, "alfie"], > > [5, "2009-08-24", 1, "cliff"], > > [4, "2009-08-21", 1, "cliff", "bob"] ] > > > > data.sort_by {|id, date, num, name| [name, date, id] } > > > > gives me: > > > > [2, "2009-08-21", 2, "alfie"] > > [3, "2009-08-23", 3, "alfie"] > > [6, "2009-08-23", 3, "alfie"] > > [1, "2009-08-21", 4, "barny"] > > [4, "2009-08-21", 1, "cliff", "bob"] > > [5, "2009-08-24", 1, "cliff"] > > > > Thanks David, > > I think I know what the happened now. When I tried the other > approach, I sorted in place using: data.sort! > > But when I used "data.sort_by" it might have sorted it but didn't save > it back to the same array. > > "sort_by!" doesn't exist so I'll need to save the sorted data to > another variable. > > The sort with the sample data above works as I expect, but for some > reason it still isn't sorting correctly with my real data. I'll keep > looking at it. I must be missing something else, although I can't > think what it might be right now. > > Sort the data, write it out to file. Should be straightforward. > > Cheers. > > I got the same answer as David, those last two should compare "cliff" to "cliff" and decide they are the same, then move to dates, which are all the same except the last character. So the one with the date ending in "21" should be before the one with the date ending in "24". This is what I saw when I tried it. Here are some other things you can do, to help you deal with the sometimes last name issue. If you are using names, you can use a variable that takes an arbitrary number of arguments. Something like *name, then if there is one name there, or two, they both get put into name, which is an array. So if the name was "barney" then the variable would look like ["barney"] and if there was also a last name that was "rubble" then the variable would look like ["barney","rubble"]. If you are not naming your variables, but instead using indexes, you can access then by submitting a range, like this d[2..-1] which says to return a new array of values starting at index 2 (I think name was index 3 with your data), and through index -1. So it will do the same as the above. Here are a few examples. def pi( heading , to_inspect ) puts '' , heading to_inspect.each{ |d| p d } end data = [ [ 5 , :foo , "alfie" ] , [ 1 , :bar , "barney" , "rubble" ] , [ 1 , :boo , "barney" , "fife" ] , [ 1 , :far , "alfie" ] ] puts 'sorting by name, then by id' pi "with sort" , data.sort { |(a_id,a_whatever,*a_name) , (b_id,b_whatever,*b_name)| first = a_name <=> b_name first.zero? ? a_id <=> b_id : first } #using brackets so it is a block to sort, not pi pi "with sort_by" , data.sort_by{ |d| [d[2..-1],d[0]] } pi "with sort_by" , data.sort_by{ |id,whatever,*name| [name,id] } --000e0cd241c65a11a30472606d6e--