On Sep 14, 2007, at 8:42 AM, Dan Zwell wrote:
> Axel Etzold wrote:
>> Dear all,
>> I have many arrays like
>> a=[{'a',10,'b',3},{'a',10,'b',4},{'a',5,'b',13},{'a',13,'b',13},
>> {'a',10,'b',7},{'a',5,'b',3}]
>> which I'd like to sort such that I get the hashes with the highest
>> values of 'a' first. If there are ties, I'd like to sort them (but  
>> not
>> the entire array) such
>> that the highest values of 'b' come first.
>> So I can't just sort for 'a'-values first and then for 'b'-values,
>> as this would destroy the first sort order.
>> Is there a built-in way of getting the ties in sorting, such as an
>> Array of the results of the <=> comparisons ?
>> Thank you!
>> Best regards,
>> Axel
>
> Built in? I don't know about that, but it's pretty easy. I'm sure  
> your real situation is more complex than the example you gave, but  
> I really think this is the easiest way (and you can avoid making  
> comparisons twice by caching the value of hash1['a'] <=> hash2 
> ['a'], if you wish):
>
> a=[{'a',10,'b',3},{'a',10,'b',4},{'a',5,'b',13},{'a',13,'b',13},
> {'a',10,'b',7},{'a',5,'b',3}]
> a.sort do |hash1, hash2|
>   if hash1['a'] == hash2['a']
>     hash1['b'] <=> hash2['b']
>   else
>     hash1['a'] <=> hash2['a']
>   end
> end
>
> The above is essentially a redefinition of <=> on hashes with  
> elements "a" and "b". The only thing you need to be sure of is that  
> ordering is strict--that you never have x < y < z but z < x. That  
> should be no problem if you only try to break ties.
>
> Hope this helps,
> Dan

a.sort do |h1,h2|
   (h1['a'] <=> h2['a']).nonzero? || h1['b'] <=> h2['b']
end

The Numeric#nonzero? is exactly for this kind of thing.  If its  
receiver is 0 it returns nil so chaining with || will work.  (And you  
don't have to compare the 'a' values twice.)

-Rob

Rob Biedenharn		http://agileconsultingllc.com
Rob / AgileConsultingLLC.com