Finding ties in sorting?

Discussion in 'Ruby' started by Axel Etzold, Sep 14, 2007.

  1. Axel Etzold

    Axel Etzold Guest

    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
    --
    Psssst! Schon vom neuen GMX MultiMessenger gehört?
    Der kanns mit allen: http://www.gmx.net/de/go/multimessenger
     
    Axel Etzold, Sep 14, 2007
    #1
    1. Advertising

  2. Alle venerd=EC 14 settembre 2007, Axel Etzold ha scritto:
    > Dear all,
    >
    > I have many arrays like
    >
    > a=3D[{'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 <=3D> comparisons ?
    >
    > Thank you!
    >
    > Best regards,
    >
    > 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=
    =20
    tie, the values of 'b', both in ascending order. Applying reverse to this=20
    array gives you the correct order. The result is the following:

    [{"a"=3D>13, "b"=3D>13}, {"a"=3D>10, "b"=3D>7}, {"a"=3D>10, "b"=3D>4}, {"a"=
    =3D>10, "b"=3D>3},=20
    {"a"=3D>5, "b"=3D>13}, {"a"=3D>5, "b"=3D>3}]

    I hope this helps

    Stefano
     
    Stefano Crocco, Sep 14, 2007
    #2
    1. Advertising

  3. Axel Etzold

    Dan Zwell Guest

    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
     
    Dan Zwell, Sep 14, 2007
    #3
  4. 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 Biedenharn, Sep 14, 2007
    #4
  5. Axel Etzold

    Dan Zwell Guest

    Rob Biedenharn 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
     
    Dan Zwell, Sep 14, 2007
    #5
    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. Andrew Thompson

    Code that ties up the compiler

    Andrew Thompson, Nov 26, 2008, in forum: Java
    Replies:
    1
    Views:
    307
    Roedy Green
    Nov 27, 2008
  2. Replies:
    2
    Views:
    1,489
    James Kanze
    Jul 6, 2010
  3. Michael Angelo Ravera

    Ranking an array (with ties and tollerances)

    Michael Angelo Ravera, Aug 17, 2011, in forum: C Programming
    Replies:
    13
    Views:
    585
    Michael Angelo Ravera
    Aug 21, 2011
  4. Andrew Hamm

    Chains of ties

    Andrew Hamm, Jul 9, 2004, in forum: Perl Misc
    Replies:
    0
    Views:
    129
    Andrew Hamm
    Jul 9, 2004
  5. kj
    Replies:
    8
    Views:
    163
    phaylon
    Mar 14, 2005
Loading...

Share This Page