# Finding ties in sorting?

**URL:** <https://www.ruby-forum.com/t/finding-ties-in-sorting/114704>\
**Category:** Ruby\
**Created:** [September 17, 2007, 1:24pm UTC](https://www.ruby-forum.com/t/finding-ties-in-sorting/114704 "2007-09-17T13:24:33Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Axel\_E](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/7c8e57/32.png) [@Axel\_E](https://www.ruby-forum.com/u/Axel_E)\
**Post date:** [September 17, 2007, 1:24pm UTC](https://www.ruby-forum.com/t/finding-ties-in-sorting/114704/1 "2007-09-17T13:24:33Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Axel\_E](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/7c8e57/32.png) [@Axel\_E](https://www.ruby-forum.com/u/Axel_E)\
**Post date:** [September 25, 2007, 11:04pm UTC](https://www.ruby-forum.com/t/finding-ties-in-sorting/114704/2 "2007-09-25T23:04:25Z")

</div>

Rob B. wrote:

> 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

Neat, I didn’t know about that.

Dan

---

<div class="post-metadata">

**Author:** ![Axel\_E](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/7c8e57/32.png) [@Axel\_E](https://www.ruby-forum.com/u/Axel_E)\
**Post date:** [September 25, 2007, 11:05pm UTC](https://www.ruby-forum.com/t/finding-ties-in-sorting/114704/3 "2007-09-25T23:05:26Z")

</div>

Axel E. wrote:

> that the highest values of ‘b’ come first.  
> 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

---

<div class="post-metadata">

**Author:** ![Axel\_E](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/7c8e57/32.png) [@Axel\_E](https://www.ruby-forum.com/u/Axel_E)\
**Post date:** [September 25, 2007, 11:05pm UTC](https://www.ruby-forum.com/t/finding-ties-in-sorting/114704/4 "2007-09-25T23:05:33Z")

</div>

Alle venerdì 14 settembre 2007, Axel E. ha scritto:

> that the highest values of ‘b’ come first.  
> Axel  
> This should work:

a.sort\_by{|i| [i[‘a’], i[‘b’]]}.reverse

a.sort\_by returns the hashes sorted by the values of ‘a’ and, in case of  
a  
tie, the values of ‘b’, both in ascending order. Applying reverse to  
this  
array gives you the correct order. The result is the following:

[{“a”=\>13, “b”=\>13}, {“a”=\>10, “b”=\>7}, {“a”=\>10, “b”=\>4}, {“a”=\>10,  
“b”=\>3},  
{“a”=\>5, “b”=\>13}, {“a”=\>5, “b”=\>3}]

I hope this helps

Stefano

---

<div class="post-metadata">

**Author:** ![Axel\_E](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/7c8e57/32.png) [@Axel\_E](https://www.ruby-forum.com/u/Axel_E)\
**Post date:** [September 25, 2007, 11:06pm UTC](https://www.ruby-forum.com/t/finding-ties-in-sorting/114704/5 "2007-09-25T23:06:16Z")

</div>

On Sep 14, 2007, at 8:42 AM, Dan Z. wrote:

> > So I can’t just sort for ‘a’-values first and then for ‘b’-values,  
> > comparisons twice by caching the value of hash1[‘a’] \<=\> hash2  
> > 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 B. [http://agileconsultingllc.com](http://agileconsultingllc.com)  
removed\_email\_address@domain.invalid
