[Nuby] Sorting a Hash and keepint it as a Hash?

Discussion in 'Ruby' started by Williams, Chris, Dec 13, 2004.

  1. ------_=_NextPart_001_01C4E14F.4AE3BE3B
    Content-Type: text/plain;
    charset="us-ascii"
    Content-Transfer-Encoding: quoted-printable

    Another nuby question:

    I have a Hash of objects which I want to sort by the values. Afterwards
    I want to pull out the keys as one array and the values as another. So I
    have code like so:

    # sort by frequency ascending
    @fault_sums =3D @fault_sums.sort {|a,b| a[1] <=3D> b[1]}
    # Only keep top N
    @fault_sums.slice!(0...-@number) if @number <=3D @fault_sums.size=20
    =20
    fields =3D @fault_sums.keys
    data =3D @fault_sums.values

    But when I get to calling keys and values on the Hash I realized, sort
    actually returns back a 2D array and those methods aren't defined on an
    Array. Is there a way to make the 2D Array returned by the sort back
    into a Hash?

    Thanks,
    Chris Williams

    ------_=_NextPart_001_01C4E14F.4AE3BE3B--
    Williams, Chris, Dec 13, 2004
    #1
    1. Advertising

  2. On Tue, 14 Dec 2004 05:07:03 +0900, Williams, Chris
    <> wrote:
    > Another nuby question:
    >
    > I have a Hash of objects which I want to sort by the values. Afterwards
    > I want to pull out the keys as one array and the values as another. So I
    > have code like so:
    >
    > # sort by frequency ascending
    > @fault_sums = @fault_sums.sort {|a,b| a[1] <=> b[1]}
    > # Only keep top N
    > @fault_sums.slice!(0...-@number) if @number <= @fault_sums.size
    >
    > fields = @fault_sums.keys
    > data = @fault_sums.values
    >
    > But when I get to calling keys and values on the Hash I realized, sort
    > actually returns back a 2D array and those methods aren't defined on an
    > Array. Is there a way to make the 2D Array returned by the sort back
    > into a Hash?
    >
    > Thanks,
    > Chris Williams
    >
    >

    Well you could but you'd be back at square one since a hash is
    unordered. An alternate method is to sort the keys by the values, ie

    keys_ordered = some_hash.keys.sort { |a, b| some_hash[a] <=> some_hash }

    keys_ordered.each { |k|
    # do something with some_hash[k]
    }

    Of course you'll have to change it to fit exactly what you need.
    Logan Capaldo, Dec 13, 2004
    #2
    1. Advertising

  3. >
    > "Williams, Chris" <> schrieb im Newsbeitrag
    > news:...
    > Another nuby question:
    >
    > I have a Hash of objects which I want to sort by the values. Afterwards
    > I want to pull out the keys as one array and the values as another. So I
    > have code like so:


    You want sort with a block:

    >> h={1=>"a",2=>"b"}

    => {1=>"a", 2=>"b"}
    >> h.sort {|(k1,v1),(k2,v2)| v1 <=> v2}

    => [[1, "a"], [2, "b"]]

    If you use inject you can get your two arrays in one go:

    >> h.sort {|(k1,v1),(k2,v2)| v1 <=> v2}.inject([[],[]]) {|(ks,vs),(k,v)| ks
    >> << k; vs << v; [ks,vs]}

    => [[1, 2], ["a", "b"]]
    >> keys, values = h.sort {|(k1,v1),(k2,v2)| v1 <=> v2}.inject([[],[]])
    >> {|(ks,vs),(k,v)| ks << k; vs << v; [ks,vs]}

    => [[1, 2], ["a", "b"]]
    >> keys

    => [1, 2]
    >> values

    => ["a", "b"]

    > # sort by frequency ascending
    > @fault_sums = @fault_sums.sort {|a,b| a[1] <=> b[1]}
    > # Only keep top N
    > @fault_sums.slice!(0...-@number) if @number <= @fault_sums.size
    >
    > fields = @fault_sums.keys
    > data = @fault_sums.values
    >
    > But when I get to calling keys and values on the Hash I realized, sort
    > actually returns back a 2D array and those methods aren't defined on an
    > Array. Is there a way to make the 2D Array returned by the sort back
    > into a Hash?


    This won't help as the hash you get then is unsorted again. If you need a
    copy, Hash#dup or Marshal.load(Marshal.dump(hash)) is a better choice.

    Kind regards

    robert
    Robert Klemme, Dec 13, 2004
    #3
  4. Williams, Chris wrote:

    > I have a Hash of objects which I want to sort by the values. Afterwards
    > I want to pull out the keys as one array and the values as another. So I
    > have code like so:
    >
    > # sort by frequency ascending
    > @fault_sums = @fault_sums.sort {|a,b| a[1] <=> b[1]}
    > # Only keep top N
    > @fault_sums.slice!(0...-@number) if @number <= @fault_sums.size
    >
    > fields = @fault_sums.keys
    > data = @fault_sums.values
    >
    > But when I get to calling keys and values on the Hash I realized, sort
    > actually returns back a 2D array and those methods aren't defined on an
    > Array. Is there a way to make the 2D Array returned by the sort back
    > into a Hash?


    There's no sorted Hashs in Standard Ruby so you will get a sorted Array
    of pairs.

    However you can use a nifty trick to get the keys and values out of that:

    [['key1', 'value1'], ['key2', 'value2']].transpose
    # => [['key1', 'key2'], ['value1', 'value2']]

    So this will solve your problem:

    top_pairs = @faults_sum.sort_by { |key, value| -value }.first(@number)
    fields, data = *top_pairs.transpose

    Note that I chose to sort descending and to keep the first (high sum)
    entries instead of sorting ascending and to keep the lowest (high sum)
    entries in reverse.
    Florian Gross, Dec 13, 2004
    #4
    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. rp
    Replies:
    1
    Views:
    517
    red floyd
    Nov 10, 2011
  2. Peña, Botp
    Replies:
    1
    Views:
    232
    Robert Klemme
    Jan 24, 2004
  3. Alexey Verkhovsky
    Replies:
    5
    Views:
    137
    Ara.T.Howard
    Jul 22, 2004
  4. larry
    Replies:
    6
    Views:
    160
    Farrel Lifson
    Mar 9, 2006
  5. IanW
    Replies:
    3
    Views:
    125
    Ian Stuart
    Dec 14, 2005
Loading...

Share This Page