Ask a Question related to Ruby, Design and Development.

  1. #1

    Default Sorting a Hash

    I'm Having some trouble sorting a hash!, the hash contents are like
    this:

    1 is Ayumi Hamasaki
    2 is Zone
    1 is Two-Mix
    2 is Shazna
    1 is L'arc~en~ciel

    Problem is: I want to ordered it in a descending order but using
    Hash.invert I lose data 'cos there can't be several keys that are the
    same, so any ideas of how to do this

    this is the code the comments are there 'cos they del some data
    ---------------CODE------------------------
    jdir="E:/emusic/jrock"
    Dir.chdir(jdir)
    jlist=Array.new
    jlist=Dir.entries(jdir)
    jlist.sort!
    $serie=Array.new
    $jcount=Hash.new()
    jlist.each do |entry|
    $serie=entry.sub(/ - +[a-zA-Z0-9\-.!=&+~\(\) ']*/,'')
    if($jcount.has_key?($serie))
    $jcount[$serie]=$jcount[$serie]+1
    else
    $jcount.store($serie,1)
    end
    end
    #$jcount=$jcount.invert
    #$jcount=$jcount.sort
    #$jcount.reverse!
    $jcount.each {|key, value| print value, " is ", key, "\n" }
    ---------------CODE------------------------

    comments on the regexp are also welcomed
    "artist - name(~=live'now-now'~[what])-.mp3" to "artist"
    Osuka Guest

  2. Similar Questions and Discussions

    1. Sorting Hash of Hashes with HEAP module
      Hi, I would like to use the Heap module from CPAN to sort Hash of Hashes by values, keeping track of what pairs of keys belong to what values. ...
    2. hash sorting
      On 12/15/2003 3:17 AM, B. Rothstein wrote: Check the Perl FAQ.
    3. avoid repitive code while sorting hash arrays
      suppose I have a hash like %users =( 'cvs' => { 'uname' => 'cvs', 'uid' => 582, 'gid' => 500 }, 'radvd' => { 'uname' => 'radvd',
    4. Sorting Hash of teams for premier league table
      This is what the hash looks like (with only 4 teams in it) ignore the Competition: { 'Team' => , 'Competition' => } ] }
    5. sorting on hash contents
      Hi, all. Say I have a hash of 4 elements, val and name h = "1,2,3,fred" h = "4,1,2,jack" h = "3,3,4,jill" How do I define:
  3. #2

    Default Re: Sorting a Hash

    Brian Candler <B.Candler@pobox.com> wrote in message news:<20030701112013.A20127@linnet.org>...
    > On Tue, Jul 01, 2003 at 07:07:55PM +0900, Osuka wrote:
    > > I'm Having some trouble sorting a hash!, the hash contents are like
    > > this:
    > >
    > > 1 is Ayumi Hamasaki
    > > 2 is Zone
    > > 1 is Two-Mix
    > > 2 is Shazna
    > > 1 is L'arc~en~ciel
    >
    > I don't understand. Firstly, do you mean that your hash is like this:
    >
    > myhash = {
    > 'Ayumi Hamasaki' => 1,
    > 'Zone' => 2,
    > 'Two-Mix' => 1,
    > 'Shazna' => 2,
    > 'L\'Arc~en~ciel' => 1,
    > }
    >
    Sorry about that!! but you got the right idea!!
    > Secondly, how do you want to sort it? If you just do
    >
    > myhash.sort
    >
    > then you will get it sorted alphabetically by the key, i.e.
    >
    > => [["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1], ["Shazna", 2],
    > ["Two-Mix", 1], ["Zone", 2]]
    >
    > If you want to sort it by the numeric value, then you can pass in an
    > explicit block which shows how to compare the values:
    >
    > myhash.sort {|x,y| x[1] <=> y[1]}
    >
    > => [["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1], ["Two-Mix", 1],
    > ["Shazna", 2], ["Zone", 2]]
    >
    > (you can see all the 1's come before the 2's)
    Arrg I did tried this and the to_a approach but i forgot something way
    too simple! if myhash.sort {|x,y| x[1] <=> y[1]} does return the
    sorted array but doesn't actually affects the given array so I have to
    assign the returned value to the hash I'm using, how come I miss it!!!
    all the problem was here!!

    Yes I want it sorted by descending values not alphabetical
    [["Shazna", 2],["Zone", 2],["Ayumi Hamasaki", 1], ["L'Arc~en~ciel",
    1], ["Two-Mix", 1]]
    >
    > Essentially the thing to remember is: when you sort a hash, it first gets
    > converted to an array, where each element is a two-element array of
    > [key,value] pairs.
    >
    > You can do this conversion yourself explicitly:
    >
    > myhash.to_a
    >
    > > Problem is: I want to ordered it in a descending order but using
    > > Hash.invert I lose data 'cos there can't be several keys that are the
    > > same, so any ideas of how to do this
    >
    > By descending order of what?
    >
    > Hash.invert doesn't reverse the order of elements, it swaps the keys and the
    > values!! If you want a reverse alphabetical sort, try:
    >
    > myhash.sort.reverse
    >
    > => [["Zone", 2], ["Two-Mix", 1], ["Shazna", 2], ["L'Arc~en~ciel", 1],
    > ["Ayumi Hamasaki", 1]]
    >
    yes values become keys and keys values, that's why it was "working"
    but eliminating some new keys ie duplicated ones. doing a reverse then
    converting to an array meaned that I could easily get it sorted as I
    wanted but I would lose elements because of key duplicates, which its
    my fault for not considering that a lot of the values are identical.
    > Regards,
    >
    > Brian.
    well thanks!! now it works and sorry for a not so clear post.
    Osuka Guest

  4. #3

    Default Re: Sorting a Hash

    On Wed, Jul 02, 2003 at 01:50:30AM +0900, Osuka wrote:
    > > If you want to sort it by the numeric value, then you can pass in an
    > > explicit block which shows how to compare the values:
    > >
    > > myhash.sort {|x,y| x[1] <=> y[1]}
    > >
    > > => [["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1], ["Two-Mix", 1],
    > > ["Shazna", 2], ["Zone", 2]]
    > >
    > > (you can see all the 1's come before the 2's)
    >
    > Arrg I did tried this and the to_a approach but i forgot something way
    > too simple! if myhash.sort {|x,y| x[1] <=> y[1]} does return the
    > sorted array but doesn't actually affects the given array so I have to
    > assign the returned value to the hash I'm using, how come I miss it!!!
    > all the problem was here!!
    Of course, the result of the sort is an array, not a hash. There's no point
    trying to put the elements back into a hash, because a hash is _unordered_
    by definition. Effectively they would end up in a random order again.
    > Yes I want it sorted by descending values not alphabetical
    > [["Shazna", 2],["Zone", 2],["Ayumi Hamasaki", 1], ["L'Arc~en~ciel",
    > 1], ["Two-Mix", 1]]
    Ah OK. Actually quite a nice solution is:

    myhash.sort { |x,y| y[1] <=> x[1] }

    or even better,

    myhash.sort { |x,y| y.reverse <=> x.reverse }

    The 'reverse' swaps x[0]/x[1], so it sorts by the number before sorting by
    the name. Using y...<=>...x gives a sort in reverse order. So this will
    group together all the entries by number, sorted in reverse numeric order,
    and within groups it will sort by reverse alphabetic order.

    If you want reverse numeric and forward alphabetic, you can get a bit more
    imaginative with the contents of the comparison function:

    myhash.sort { |x,y|
    cmp = y[1] <=> x[1]
    if cmp != 0
    cmp
    else
    x[0] <=> y[0]
    end
    }

    => [["Shazna", 2], ["Zone", 2], ["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1],
    ["Two-Mix", 1]]

    Cheers,

    Brian.

    Brian Candler Guest

  5. #4

    Default Re: Sorting a Hash

    Brian Candler <B.Candler@pobox.com> wrote in message news:<20030701211409.GA66745@uk.tiscali.com>...
    > On Wed, Jul 02, 2003 at 01:50:30AM +0900, Osuka wrote:
    > > > If you want to sort it by the numeric value, then you can pass in an
    > > > explicit block which shows how to compare the values:
    > > >
    > > > myhash.sort {|x,y| x[1] <=> y[1]}
    > > >
    > > > => [["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1], ["Two-Mix", 1],
    > > > ["Shazna", 2], ["Zone", 2]]
    > > >
    > > > (you can see all the 1's come before the 2's)
    > >
    > > Arrg I did tried this and the to_a approach but i forgot something way
    > > too simple! if myhash.sort {|x,y| x[1] <=> y[1]} does return the
    > > sorted array but doesn't actually affects the given array so I have to
    > > assign the returned value to the hash I'm using, how come I miss it!!!
    > > all the problem was here!!
    >
    > Of course, the result of the sort is an array, not a hash. There's no point
    > trying to put the elements back into a hash, because a hash is _unordered_
    > by definition. Effectively they would end up in a random order again.
    >
    > > Yes I want it sorted by descending values not alphabetical
    > > [["Shazna", 2],["Zone", 2],["Ayumi Hamasaki", 1], ["L'Arc~en~ciel",
    > > 1], ["Two-Mix", 1]]
    >
    > Ah OK. Actually quite a nice solution is:
    >
    > myhash.sort { |x,y| y[1] <=> x[1] }
    >
    > or even better,
    >
    > myhash.sort { |x,y| y.reverse <=> x.reverse }
    >
    > The 'reverse' swaps x[0]/x[1], so it sorts by the number before sorting by
    > the name. Using y...<=>...x gives a sort in reverse order. So this will
    > group together all the entries by number, sorted in reverse numeric order,
    > and within groups it will sort by reverse alphabetic order.
    >
    > If you want reverse numeric and forward alphabetic, you can get a bit more
    > imaginative with the contents of the comparison function:
    >
    > myhash.sort { |x,y|
    > cmp = y[1] <=> x[1]
    > if cmp != 0
    > cmp
    > else
    > x[0] <=> y[0]
    > end
    > }
    >
    > => [["Shazna", 2], ["Zone", 2], ["Ayumi Hamasaki", 1], ["L'Arc~en~ciel", 1],
    > ["Two-Mix", 1]]
    >
    > Cheers,
    >
    > Brian.
    Yes I mistyped there!! I tried to mean the array returned, 'cos the
    hash its no more after a sort, I should be more careful with those
    words. And thanks a lot Brian I didn't thought of doing an
    alphabetical(as secondary rule) sort after the numerical, I guess that
    was coming even in the example that I gave on what I wanted I did it
    like that.Now it all works and as a little exercise I turned it into a
    class(a bit of overkill but...gotta learn)
    Osuka Guest

  6. #5

    Default Re: Sorting a Hash

    On Thu, Jul 03, 2003 at 08:24:37AM +0900, Osuka wrote:
    > Now it all works and as a little exercise I turned it into a
    > class(a bit of overkill but...gotta learn)
    I don't think it's overkill at all. In Ruby it often makes sense to make a
    class even for simple cases.

    Your code will probably be clearer because the class will have its own <=>
    compare method, so you can sort those objects in their preferred order
    without having to write that magic compare block each time.

    Cheers,

    Brian.

    Brian Candler Guest

Posting Permissions

  • You may not post new threads
  • You may post replies
  • You may not post attachments
  • You may not edit your posts

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139