# Sorting an array based on two attributes of objects

**URL:** <https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165>\
**Category:** Ruby\
**Created:** [March 26, 2007, 3:56pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165 "2007-03-26T15:56:52Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![senthil](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@senthil](https://www.ruby-forum.com/u/senthil)\
**Post date:** [March 26, 2007, 3:56pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165/1 "2007-03-26T15:56:52Z")

</div>

Thanks for some of your replies for the lst post i need small  
modification in that post … i want to sort the salary in descending  
order. i have explained the same quesion again…

Hi all,  
I want to sort the objects of array based on two attributes.I want  
sort an employee class based on his salary in descecding order and name  
, so that if two  
person has same salary it should be sorted with name.  
Lets say for example the employee objects has following name and  
salary.

```
     name salary
       d 100
       c 200
       b 50
       a 100

 so in this case the result which i expect is

     name salary
       b 200
       a 100
       d 100
       c 50

```

Note:In the above example for salary 100 the sorting is done  
alphabetically, but initially(before sorting) ‘d’ came first and then  
‘a’ came.so basically i want to sort the array with more than one order.  
Can any one help me to solve it ??

---

<div class="post-metadata">

**Author:** ![senthil](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@senthil](https://www.ruby-forum.com/u/senthil)\
**Post date:** [March 26, 2007, 4:12pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165/2 "2007-03-26T16:12:13Z")

</div>

senthil wrote:

> salary.  
> name salary  
> b 200  
> a 100  
> d 100  
> c 50
> 
> Note:In the above example for salary 100 the sorting is done  
> alphabetically, but initially(before sorting) ‘d’ came first and then  
> ‘a’ came.so basically i want to sort the array with more than one order.  
> Can any one help me to solve it ??

In this case, just invert the salary:

sorted\_employees = employees.sort\_by { |e| [-e.salary, e.name] }

I can’t think of a way offhand to have different lexicographic orderings  
in the same sort, though.

---

<div class="post-metadata">

**Author:** ![senthil](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@senthil](https://www.ruby-forum.com/u/senthil)\
**Post date:** [March 26, 2007, 4:18pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165/3 "2007-03-26T16:18:21Z")

</div>

senthil wrote:

> Thanks for some of your replies for the lst post i need small  
> modification in that post … i want to sort the salary in descending  
> order. i have explained the same quesion again…

I came up with this which is sub par as I test for a condition twice so  
stay tuned for a better solution…

irb(main):001:0\> [[‘d’,100],[‘c’,200],[‘b’,50],[‘a’,100]].sort {|a,b|  
b[1]==a[1]?a[0]\<=\>b[0]:b[1]\<=\>a[1]}  
=\> [[“c”, 200], [“a”, 100], [“d”, 100], [“b”, 50]]

hope this helps

ilan

---

<div class="post-metadata">

**Author:** ![senthil](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@senthil](https://www.ruby-forum.com/u/senthil)\
**Post date:** [March 26, 2007, 4:19pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165/4 "2007-03-26T16:19:59Z")

</div>

Alex Y. wrote:

> sorted\_employees = employees.sort\_by { |e| [-e.salary, e.name] }
> 
> I can’t think of a way offhand to have different lexicographic orderings  
> in the same sort, though.

Doh!!! Ofcourse! Ok… more coffee for me…

ilan

---

<div class="post-metadata">

**Author:** ![senthil](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@senthil](https://www.ruby-forum.com/u/senthil)\
**Post date:** [March 26, 2007, 5:08pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165/5 "2007-03-26T17:08:25Z")

</div>

On Mar 26, 2007, at 10:18 AM, Ilan B. wrote:

> irb(main):001:0\> [[‘d’,100],[‘c’,200],[‘b’,50],[‘a’,100]].sort {|a,b|  
> b[1]==a[1]?a[0]\<=\>b[0]:b[1]\<=\>a[1]}  
> =\> [[“c”, 200], [“a”, 100], [“d”, 100], [“b”, 50]]
> 
> hope this helps
> 
> ilan

Just to add a bit to this: consider using .nonzero? for chained  
comparisons

[[‘d’,100],[‘c’,200],[‘b’,50],[‘a’,100]].  
sort {|a,b| (b[1]\<=\>a[1]).nonzero? || a[0]\<=\>b[0] }

-Rob

Rob B. [http://agileconsultingllc.com](http://agileconsultingllc.com)  
removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![senthil](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@senthil](https://www.ruby-forum.com/u/senthil)\
**Post date:** [March 27, 2007, 6:11pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165/6 "2007-03-27T18:11:10Z")

</div>

On 3/26/07, Alex Y. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > ```
> > Lets say for example the employee objects has following name and
> > 
> > ```
> 
> In this case, just invert the salary:
> 
> sorted\_employees = employees.sort\_by { |e| [-e.salary, e.name] }
> 
> I can’t think of a way offhand to have different lexicographic orderings  
> in the same sort, though.

Someone, in another recent thread, came up with the idea of a reverse  
proxy class something like this

class Reverse

:attr\_reader :obj

def initialize(obj)  
@obj = obj  
end

def \<=\>(other)  
other.obj \<=\> self.obj  
end

end

so let’s say you wanted to sort the names in descending order as well:  
sorted\_employees = employees.sort\_by { |e| [-e.salary,  
Reverse.new(e.name) ] }

You could even use this “reverse” proxy to change the sorting of  
salary, so that the original could be:

sorted\_employees = employees.sort\_by { |e| [ Reverse.new(e.salary),  
e.name ] }

One could quibble about the name Reverse.

–  
Rick DeNatale

My blog on Ruby  
[http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![senthil](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c89c15/32.png) [@senthil](https://www.ruby-forum.com/u/senthil)\
**Post date:** [March 27, 2007, 6:18pm UTC](https://www.ruby-forum.com/t/sorting-an-array-based-on-two-attributes-of-objects/90165/7 "2007-03-27T18:18:12Z")

</div>

Rick DeNatale wrote:

> On 3/26/07, Alex Y. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:  
>   
> class Reverse
> 
> e.name ] }  
> That’s lovely. My brain wandered off down the String#invert route, and  
> I ended up getting tied in knots over multibyte encodings. Reverse is a  
> _much_ nicer trick.
