On Wed, Jul 02, 2003 at 01:50:30AM +0900, Osuka wrote:
> > If you want to sort it by the numeric value, then you can pass in an
> > explicit block which shows how to compare the values:
> > 
> >   myhash.sort {|x,y| x[1] <=> y[1]}
> > 
> > => [["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1], ["Two-Mix", 1],
> >     ["Shazna", 2], ["Zone", 2]]
> > 
> > (you can see all the 1's come before the 2's)
> 
> Arrg I did tried this and the to_a approach but i forgot something way
> too simple! if myhash.sort {|x,y| x[1] <=> y[1]} does return the
> sorted array but doesn't actually affects the given array so I have to
> assign the returned value to the hash I'm using, how come I miss it!!!
> all the problem was here!!

Of course, the result of the sort is an array, not a hash. There's no point
trying to put the elements back into a hash, because a hash is _unordered_
by definition. Effectively they would end up in a random order again.

> Yes I want it sorted by descending values not alphabetical
> [["Shazna", 2],["Zone", 2],["Ayumi Hamasaki", 1], ["L'Arc~en~ciel",
> 1], ["Two-Mix", 1]]

Ah OK. Actually quite a nice solution is:

    myhash.sort { |x,y| y[1] <=> x[1] }

or even better,

    myhash.sort { |x,y| y.reverse <=> x.reverse }

The 'reverse' swaps x[0]/x[1], so it sorts by the number before sorting by
the name. Using y...<=>...x gives a sort in reverse order. So this will
group together all the entries by number, sorted in reverse numeric order,
and within groups it will sort by reverse alphabetic order.

If you want reverse numeric and forward alphabetic, you can get a bit more
imaginative with the contents of the comparison function:

    myhash.sort { |x,y|
      cmp = y[1] <=> x[1]
      if cmp != 0
        cmp
      else
        x[0] <=> y[0]
      end
    }

=> [["Shazna", 2], ["Zone", 2], ["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1],
["Two-Mix", 1]]

Cheers,

Brian.