FAQ
Thanks for the feedback--maybe I screwed up but what happens for me is that
the ordered array (1) only lists the keys, not the array values the hash key
points to and (2) I still don't get an ordered list of the keys that are put
in the "ordered" array--it comes out un-ordered.

I took your line and just added a for loop/print for the ordered array and
got "red,yellow,blue, orange, violet, green" only as the result.

I must be dense but using just a Keys expression can't return the values,
can it??--wouldn't it be better to do a while/each and get both key and
value for the HofA somehow??

-----Original Message-----
From: James Edward Gray II
Sent: Wednesday, February 18, 2004 6:49 PM
To: Smith Jeff D
Cc: beginners@perl.org
Subject: Re: An Old Question on Sorting Hash of Arrays by Array element and
th en by key

On Feb 18, 2004, at 1:58 PM, Smith Jeff D wrote:

I am trying to sort a hash of arrays that is similar to the example
below.
I have a hash of arrays that I want to sort, first by the first
element of
the array, then by the key to the hash and don't care about other
elements
of the array (for sorting and without regard to case.

%HofA = (orange=>['ZZZ', 'ANDY'],
red=>['AAA', 'AL'],
blue=>['mmm','Betty'],
yellow=>['aaa', 'ZEUS'],
green=>['DDD','Mary Joe']
violet=>['MMM','Hugo']
);
my @ordered_keys = sort { $HofA{$a}[0] cmp $HofA{$b}[1]
$a cmp $b } keys %HofA;

I believe that will do it. See if that gets you going.

James

Search Discussions

  • WC -Sx- Jones at Feb 19, 2004 at 4:33 pm

    Smith Jeff D wrote:
    Thanks for the feedback--maybe I screwed up but what happens for me is that
    the ordered array (1) only lists the keys, not the array values the hash key
    points to and (2) I still don't get an ordered list of the keys that are put
    in the "ordered" array--it comes out un-ordered.

    Perl uses its own internal storage method for Hashes.
    There is no guarantee of order unless you sort it and
    save the results yourself.

    I took your line and just added a for loop/print for the ordered array and
    got "red,yellow,blue, orange, violet, green" only as the result.

    I must be dense but using just a Keys expression can't return the values,
    can it??--wouldn't it be better to do a while/each and get both key and
    value for the HofA somehow??

    You need the key value to get the hash data.
    Keys, in of themselves, are of little value.


    -----Original Message-----
    %HofA = (orange=>['ZZZ', 'ANDY'],
    red=>['AAA', 'AL'],
    blue=>['mmm','Betty'],
    yellow=>['aaa', 'ZEUS'],
    green=>['DDD','Mary Joe']
    violet=>['MMM','Hugo']
    );
    my @ordered_keys = sort { $HofA{$a}[0] cmp $HofA{$b}[1]
    $a cmp $b } keys %HofA;
  • James Edward Gray II at Feb 19, 2004 at 4:38 pm

    On Feb 19, 2004, at 10:25 AM, Smith Jeff D wrote:

    Thanks for the feedback--maybe I screwed up but what happens for me is
    that
    the ordered array (1) only lists the keys, not the array values the
    hash key
    points to and (2) I still don't get an ordered list of the keys that
    are put
    in the "ordered" array--it comes out un-ordered.
    First, did you catch the later post that pointed out my mistake?
    Here's the corrected code:

    my @ordered_keys = sort { $HofA{$a}[0] cmp $HofA{$b}[0]
    $a cmp $b } keys %HofA;

    I took your line and just added a for loop/print for the ordered array
    and
    got "red,yellow,blue, orange, violet, green" only as the result.

    I must be dense but using just a Keys expression can't return the
    values,
    can it??--wouldn't it be better to do a while/each and get both key and
    value for the HofA somehow??
    Yes, I only ordered the keys. Sorry if I didn't make that clear.
    That's all you need though, right? ;)

    foreach (@ordered_keys) {
    print "$HofA{$_}[0], $_, $HofA{$_}[1]\n";
    }

    Hope that helps.

    James
  • WC -Sx- Jones at Feb 19, 2004 at 4:42 pm
    %HofA = (orange=>['ZZZ', 'ANDY'],
    red=>['AAA', 'AL'],
    blue=>['mmm','Betty'],
    yellow=>['aaa', 'ZEUS'],
    green=>['DDD','Mary Joe'],
    violet=>['MMM','Hugo']
    );

    my @ordered_keys = sort { $HofA{$a}[0] cmp $HofA{$b}[1]
    $a cmp $b } keys %HofA;


    foreach $value (@ordered_keys) { print "$value\n"; }


    FYI:

    Perl Cookbook - 5.4. Traversing a Hash

    Problem -- You want to perform an action on each entry (i.e., each
    key-value pair) in a hash.

    Solution -- Use each with a while loop:

    while(($key, $value) = each(%HASH)) {
    # do something with $key and $value
    }

    Or use keys with a foreach loop, unless the hash is potentially very large:

    foreach $key (keys %HASH) {
    $value = $HASH{$key};
    # do something with $key and $value
    }

    -Sx-
  • Rob Dixon at Feb 19, 2004 at 4:45 pm

    Jeff Smith wrote:
    Thanks for the feedback--maybe I screwed up but what happens for me is that
    the ordered array (1) only lists the keys, not the array values the hash key
    points to and (2) I still don't get an ordered list of the keys that are put
    in the "ordered" array--it comes out un-ordered.

    I took your line and just added a for loop/print for the ordered array and
    got "red,yellow,blue, orange, violet, green" only as the result.

    I must be dense but using just a Keys expression can't return the values,
    can it??--wouldn't it be better to do a while/each and get both key and
    value for the HofA somehow??

    -----Original Message-----
    From: James Edward Gray II
    Sent: Wednesday, February 18, 2004 6:49 PM
    To: Smith Jeff D
    Cc: beginners@perl.org
    Subject: Re: An Old Question on Sorting Hash of Arrays by Array element and
    th en by key

    On Feb 18, 2004, at 1:58 PM, Smith Jeff D wrote:

    I am trying to sort a hash of arrays that is similar to the example
    below.
    I have a hash of arrays that I want to sort, first by the first
    element of
    the array, then by the key to the hash and don't care about other
    elements
    of the array (for sorting and without regard to case.

    %HofA = (orange=>['ZZZ', 'ANDY'],
    red=>['AAA', 'AL'],
    blue=>['mmm','Betty'],
    yellow=>['aaa', 'ZEUS'],
    green=>['DDD','Mary Joe']
    violet=>['MMM','Hugo']
    );
    my @ordered_keys = sort { $HofA{$a}[0] cmp $HofA{$b}[1]
    $a cmp $b } keys %HofA;

    I believe that will do it. See if that gets you going.
    Hi Jeff.

    James was offering you a starting place. The only way to order
    a hash is to order its keys, hence 'my @ordered_keys'. What you
    do with this sorted list depends on what you want. For instance

    foreach (@ordered_keys) {
    printf "%s => %s\n", $_, $HofA{$_};
    }

    Also, I wasn't sure whether, by
    (for sorting and without regard to case)
    you meant that the string comparisons for the sort should be
    case-insensitive. If so, then your sort should look like

    my @ordered_keys = sort {
    my ($aa, $bb) = lc $a, lc $b;
    $HofA{$aa}[0] cmp $HofA{$bb}[0] or $aa cmp $bb
    } keys %HofA;

    HTH,

    Rob
  • Smith Jeff D at Feb 19, 2004 at 4:49 pm
    I really need to order both the keys and one of the elements in the array
    stored as a value in the hash, preferably sort first on the first element of
    the array (my real application has four elements but the snippet I'm testing
    with has a two-element array) and then sort secondly on the key.

    So if the reference to the array stored as the hash value is called
    "$value", then there are two elements, $$value[0] and $$value[1], that it
    references, right?
    I want to sort first on $$value[0], then on the key for HofA, and to then be
    able to print a report that lists all the data I need, including the two
    sorted values plus also the other, non-sorted values stored in the HofA
    array. That way the output is easier to read and summarize for the user.

    Does this make sense? I know how to sort by keys but sort first by the
    value element and then by keys is my block...

    -----Original Message-----
    From: James Edward Gray II
    Sent: Thursday, February 19, 2004 11:37 AM
    To: Smith Jeff D
    Cc: 'beginners@perl.org'
    Subject: Re: An Old Question on Sorting Hash of Arrays by Array element an d
    th en by key

    On Feb 19, 2004, at 10:25 AM, Smith Jeff D wrote:

    Thanks for the feedback--maybe I screwed up but what happens for me is
    that
    the ordered array (1) only lists the keys, not the array values the
    hash key
    points to and (2) I still don't get an ordered list of the keys that
    are put
    in the "ordered" array--it comes out un-ordered.
    First, did you catch the later post that pointed out my mistake?
    Here's the corrected code:

    my @ordered_keys = sort { $HofA{$a}[0] cmp $HofA{$b}[0]
    $a cmp $b } keys %HofA;

    I took your line and just added a for loop/print for the ordered array
    and
    got "red,yellow,blue, orange, violet, green" only as the result.

    I must be dense but using just a Keys expression can't return the
    values,
    can it??--wouldn't it be better to do a while/each and get both key and
    value for the HofA somehow??
    Yes, I only ordered the keys. Sorry if I didn't make that clear.
    That's all you need though, right? ;)

    foreach (@ordered_keys) {
    print "$HofA{$_}[0], $_, $HofA{$_}[1]\n";
    }

    Hope that helps.

    James
  • WC -Sx- Jones at Feb 19, 2004 at 5:00 pm

    Smith Jeff D wrote:
    I really need to order both the keys and one of the elements in the array
    stored as a value in the hash, preferably sort first on the first element of
    the array (my real application has four elements but the snippet I'm testing
    with has a two-element array) and then sort secondly on the key.

    Research:

    Tie::IxHash
  • Rob Dixon at Feb 19, 2004 at 5:16 pm

    Jeff Smith wrote:
    I really need to order both the keys and one of the elements in the array
    stored as a value in the hash, preferably sort first on the first element of
    the array (my real application has four elements but the snippet I'm testing
    with has a two-element array) and then sort secondly on the key.

    So if the reference to the array stored as the hash value is called
    "$value", then there are two elements, $$value[0] and $$value[1], that it
    references, right?
    I want to sort first on $$value[0], then on the key for HofA, and to then be
    able to print a report that lists all the data I need, including the two
    sorted values plus also the other, non-sorted values stored in the HofA
    array. That way the output is easier to read and summarize for the user.

    Does this make sense? I know how to sort by keys but sort first by the
    value element and then by keys is my block...
    Hi Jeff.

    I was hoping James would be around, but, briefly:

    A hash element is a key/value pair, but it is accessed uniquely
    by its key. You can sort the elements on any function of the key,
    the value, or both; but the result will be an ordered list of keys.

    Does that help? I hope so!

    Rob
  • James Edward Gray II at Feb 19, 2004 at 8:12 pm

    On Feb 19, 2004, at 10:48 AM, Smith Jeff D wrote:

    I really need to order both the keys and one of the elements in the
    array
    stored as a value in the hash, preferably sort first on the first
    element of
    the array (my real application has four elements but the snippet I'm
    testing
    with has a two-element array) and then sort secondly on the key.
    Are you playing with the code I'm posting? :P

    I know how you would like it sorted. I did that. (Actually, I believe
    I did miss the case insensitive part, but Rob has already fixed that.)

    A Perl hash is an unordered structure. However, if we put the keys in
    the order we want and then use those to access the values, we're good
    to go. I posted a loop showing this in my last message.

    I ordered the keys based on the first value and the key itself, just
    like you said. In order to avoid more confusion though, here's a proof
    of concept:

    #!/usr/bin/perl

    use strict;
    use warnings;

    # create some data
    my %HofA = ( orange => ['ZZZ', 'ANDY'],
    red => ['AAA', 'AL'],
    blue => ['mmm','Betty'],
    yellow => ['aaa', 'ZEUS'],
    green => ['DDD','Mary Joe'],
    violet => ['MMM','Hugo'] );

    # sort it
    my @ordered_keys = sort { lc($HofA{$a}[0]) cmp lc($HofA{$b}[0])
    lc($a) cmp lc($b) } keys %HofA;

    # print it
    foreach (@ordered_keys) {
    print "$HofA{$_}[0], $_, $HofA{$_}[1]\n";
    }

    __END__

    You'll notice that the above is really just a summary of this thread.
    When I run it, I get:

    AAA, red, AL
    aaa, yellow, ZEUS
    DDD, green, Mary Joe
    mmm, blue, Betty
    MMM, violet, Hugo
    ZZZ, orange, ANDY

    Which is the output you requested in your original message.

    Hope that helps.

    James
  • Smith Jeff D at Feb 19, 2004 at 9:47 pm
    Thanks, I must have missed it--I'll be getting back to it tomorrow morning
    to see what I missed in the original response. I thought I had run as
    printed below.

    Anyway, thank for the help...I think I may have braced when I should have
    paren'd... It so simple when someone else does it first.... I was trying to
    nest the sorts rather
    than logically or'ing them together and it wasn't working.

    -----Original Message-----
    From: James Edward Gray II
    Sent: Thursday, February 19, 2004 3:12 PM
    To: Smith Jeff D
    Cc: 'beginners@perl.org'
    Subject: Re: An Old Question on Sorting Hash of Arrays by Array element an d
    th en by key

    On Feb 19, 2004, at 10:48 AM, Smith Jeff D wrote:

    I really need to order both the keys and one of the elements in the
    array
    stored as a value in the hash, preferably sort first on the first
    element of
    the array (my real application has four elements but the snippet I'm
    testing
    with has a two-element array) and then sort secondly on the key.
    Are you playing with the code I'm posting? :P

    I know how you would like it sorted. I did that. (Actually, I believe
    I did miss the case insensitive part, but Rob has already fixed that.)

    A Perl hash is an unordered structure. However, if we put the keys in
    the order we want and then use those to access the values, we're good
    to go. I posted a loop showing this in my last message.

    I ordered the keys based on the first value and the key itself, just
    like you said. In order to avoid more confusion though, here's a proof
    of concept:

    #!/usr/bin/perl

    use strict;
    use warnings;

    # create some data
    my %HofA = ( orange => ['ZZZ', 'ANDY'],
    red => ['AAA', 'AL'],
    blue => ['mmm','Betty'],
    yellow => ['aaa', 'ZEUS'],
    green => ['DDD','Mary Joe'],
    violet => ['MMM','Hugo'] );

    # sort it
    my @ordered_keys = sort { lc($HofA{$a}[0]) cmp lc($HofA{$b}[0])
    lc($a) cmp lc($b) } keys
    %HofA;

    # print it
    foreach (@ordered_keys) {
    print "$HofA{$_}[0], $_, $HofA{$_}[1]\n";
    }

    __END__

    You'll notice that the above is really just a summary of this thread.
    When I run it, I get:

    AAA, red, AL
    aaa, yellow, ZEUS
    DDD, green, Mary Joe
    mmm, blue, Betty
    MMM, violet, Hugo
    ZZZ, orange, ANDY

    Which is the output you requested in your original message.

    Hope that helps.

    James
  • James Edward Gray II at Feb 19, 2004 at 9:42 pm

    On Feb 19, 2004, at 3:20 PM, Smith Jeff D wrote:

    Thanks, I must have missed it--I'll be getting back to it tomorrow
    morning
    to see what I missed in the original response. I thought I had run as
    printed below.
    No worries. You probably did run my original response, which was
    flawed. Mark gave a fix for it shortly after I posted it. Then Rob
    pointed out that it was ignoring your case insensitive request today.
    All their suggestions are included below.

    The Moral: Don't use the original message. Use this one.
    Anyway, thank for the help...I think I may have braced when I should
    have
    paren'd... It so simple when someone else does it first.... I was
    trying to
    nest the sorts rather
    than logically or'ing them together and it wasn't working.
    Oring sort() conditions is a common Perl idiom. Now you know. ;)

    James
    #!/usr/bin/perl

    use strict;
    use warnings;

    # create some data
    my %HofA = ( orange => ['ZZZ', 'ANDY'],
    red => ['AAA', 'AL'],
    blue => ['mmm','Betty'],
    yellow => ['aaa', 'ZEUS'],
    green => ['DDD','Mary Joe'],
    violet => ['MMM','Hugo'] );

    # sort it
    my @ordered_keys = sort { lc($HofA{$a}[0]) cmp lc($HofA{$b}[0])
    lc($a) cmp lc($b) } keys
    %HofA;

    # print it
    foreach (@ordered_keys) {
    print "$HofA{$_}[0], $_, $HofA{$_}[1]\n";
    }

    __END__

    You'll notice that the above is really just a summary of this thread.
    When I run it, I get:

    AAA, red, AL
    aaa, yellow, ZEUS
    DDD, green, Mary Joe
    mmm, blue, Betty
    MMM, violet, Hugo
    ZZZ, orange, ANDY

    Which is the output you requested in your original message.

    Hope that helps.

    James
  • Rob Dixon at Feb 19, 2004 at 10:50 pm

    James Edward Gray II wrote:
    The Moral: Don't use the original message. Use this one.
    Far more reliable is: "Don't do what I say, do what I mean." :)

    Rob
  • John W. Krahn at Feb 20, 2004 at 12:55 am

    Rob Dixon wrote:

    James Edward Gray II wrote:
    The Moral: Don't use the original message. Use this one.
    Far more reliable is: "Don't do what I say, do what I mean." :)
    After all, Perl is a DWIM language. :-)


    John
    --
    use Perl;
    program
    fulfillment
  • R. Joseph Newton at Feb 20, 2004 at 5:52 pm

    Smith Jeff D wrote:

    Thanks for the feedback--maybe I screwed up but what happens for me is that
    the ordered array (1) only lists the keys, not the array values the hash key
    points to and (2) I still don't get an ordered list of the keys that are put
    in the "ordered" array--it comes out un-ordered.
    Ooops. Bad things happen when you start out too quickly specifying program
    structures. When you need an ordered array, you need to use an array, rather
    than a hash. Hashes *do not, ever* offer any warranty on internal ordering.
    What they offer instead is speedy access to string-keyed data elements.
    I took your line and just added a for loop/print for the ordered array and
    got "red,yellow,blue, orange, violet, green" only as the result.

    I must be dense but using just a Keys expression can't return the values,
    can it??--wouldn't it be better to do a while/each and get both key and
    value for the HofA somehow??
    I'm afraid your original thread got spearated from this post, so that is hard to
    say. Usually, the way to control ordering of hash output is to sort on the
    keys.

    foreach (sort {$a <=> $b} keys %my_hash) { #numeric
    foreach (sort {$a cmp $b} keys %my_hash) { #ASCII
    foreach (sort {my_compare($a, $b)} keys %my_hash) { # custom comparison
    do_things $my_hash{$_};
    }

    If there is a special ordering to the keys that cannot be expressed in a
    standard comparison function, this might be an indication that you shoud be
    using a package to hold the information, so that you can treat the data in the
    specific ordering called for in its logical context..


    Joseph
  • Smith Jeff D at Feb 20, 2004 at 9:22 pm
    It's working fine and thanks for your help---hopefully my users will welcome
    the difference.

    Thanks again.

    -----Original Message-----
    From: James Edward Gray II
    Sent: Thursday, February 19, 2004 4:42 PM
    To: Smith Jeff D
    Cc: 'beginners@perl.org'
    Subject: Re: An Old Question on Sorting Hash of Arrays by Array element an d
    th en by key

    On Feb 19, 2004, at 3:20 PM, Smith Jeff D wrote:

    Thanks, I must have missed it--I'll be getting back to it tomorrow
    morning
    to see what I missed in the original response. I thought I had run as
    printed below.
    No worries. You probably did run my original response, which was
    flawed. Mark gave a fix for it shortly after I posted it. Then Rob
    pointed out that it was ignoring your case insensitive request today.
    All their suggestions are included below.

    The Moral: Don't use the original message. Use this one.
    Anyway, thank for the help...I think I may have braced when I should
    have
    paren'd... It so simple when someone else does it first.... I was
    trying to
    nest the sorts rather
    than logically or'ing them together and it wasn't working.
    Oring sort() conditions is a common Perl idiom. Now you know. ;)

    James
    #!/usr/bin/perl

    use strict;
    use warnings;

    # create some data
    my %HofA = ( orange => ['ZZZ', 'ANDY'],
    red => ['AAA', 'AL'],
    blue => ['mmm','Betty'],
    yellow => ['aaa', 'ZEUS'],
    green => ['DDD','Mary Joe'],
    violet => ['MMM','Hugo'] );

    # sort it
    my @ordered_keys = sort { lc($HofA{$a}[0]) cmp lc($HofA{$b}[0])
    lc($a) cmp lc($b) } keys
    %HofA;

    # print it
    foreach (@ordered_keys) {
    print "$HofA{$_}[0], $_, $HofA{$_}[1]\n";
    }

    __END__

    You'll notice that the above is really just a summary of this thread.
    When I run it, I get:

    AAA, red, AL
    aaa, yellow, ZEUS
    DDD, green, Mary Joe
    mmm, blue, Betty
    MMM, violet, Hugo
    ZZZ, orange, ANDY

    Which is the output you requested in your original message.

    Hope that helps.

    James

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupbeginners @
categoriesperl
postedFeb 19, '04 at 4:26p
activeFeb 20, '04 at 9:22p
posts15
users6
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase