sorting an array based on two attributes of objects

Discussion in 'Ruby' started by senthil, Mar 26, 2007.

  1. senthil

    senthil Guest

    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 ??

    --
    Posted via http://www.ruby-forum.com/.
     
    senthil, Mar 26, 2007
    #1
    1. Advertising

  2. senthil

    Alex Young Guest

    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....
    >
    > 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 ??
    >

    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.

    --
    Alex
     
    Alex Young, Mar 26, 2007
    #2
    1. Advertising

  3. senthil

    Ilan Berci Guest

    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



    --
    Posted via http://www.ruby-forum.com/.
     
    Ilan Berci, Mar 26, 2007
    #3
  4. senthil

    Ilan Berci Guest

    Alex Young 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..

    <sulks away with his tail between his legs>

    ilan


    --
    Posted via http://www.ruby-forum.com/.
     
    Ilan Berci, Mar 26, 2007
    #4
  5. On Mar 26, 2007, at 10:18 AM, Ilan Berci wrote:
    > 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


    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 Biedenharn http://agileconsultingllc.com
     
    Rob Biedenharn, Mar 26, 2007
    #5
  6. On 3/26/07, Alex Young <> wrote:
    > 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....
    > >
    > > 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 ??
    > >

    > 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 :eek:bj

    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/
     
    Rick DeNatale, Mar 27, 2007
    #6
  7. senthil

    Alex Young Guest

    Rick DeNatale wrote:
    > On 3/26/07, Alex Young <> wrote:

    <snip>
    >> 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 :eek:bj
    >
    > 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 ] }


    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.

    --
    Alex
     
    Alex Young, Mar 27, 2007
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    0
    Views:
    374
  2. Steve Bergman
    Replies:
    12
    Views:
    10,376
    Azolex
    Apr 12, 2006
  3. Replies:
    0
    Views:
    201
  4. Robocop
    Replies:
    5
    Views:
    464
    Stephen Hansen
    Feb 6, 2009
  5. senthil
    Replies:
    3
    Views:
    103
    Augie De Blieck Jr.
    Mar 26, 2007
Loading...

Share This Page