Sort by hash vaule, an array of hash references

Discussion in 'Perl Misc' started by fahdsultan@gmail.com, Oct 6, 2005.

  1. Guest

    I have an array of hash references like so:

    $array = ( $hashref1, $hashref2, ... );

    where $hashrefn = { id => 001,
    name => username,
    count => 2020, };

    I'm trying to sort the array by the hash key 'count'.

    I've tried:
    my @array_sorted = sort { ($a->{count}) <=> ($b->{count}) } @array;
    and various ways using map-sort-map, but the data come out the other
    side unsorted.

    Any insight into the problem would be appriciated.

    thanks,

    fahd
     
    , Oct 6, 2005
    #1
    1. Advertising

  2. Paul Lalli Guest

    wrote:
    > I have an array of hash references like so:
    >
    > $array = ( $hashref1, $hashref2, ... );


    There is no array in the above code.

    Did you mean either:
    $array = [ $hashref1, $hashref2, ... ];
    or
    @array = ($hashref1, $hashref2, ...);
    ?

    >
    > where $hashrefn = { id => 001,
    > name => username,
    > count => 2020, };
    >
    > I'm trying to sort the array by the hash key 'count'.
    >
    > I've tried:
    > my @array_sorted = sort { ($a->{count}) <=> ($b->{count}) } @array;
    > and various ways using map-sort-map, but the data come out the other
    > side unsorted.


    A quick glance at that code looks correct to me. I'm inclined to
    believe you didn't define your array (or array reference) correctly.

    Please post a short but *complete* program that we can copy and paste,
    which demonstrates your error.

    Paul Lalli
     
    Paul Lalli, Oct 6, 2005
    #2
    1. Advertising

  3. Guest

    > Please post a short but *complete* program that we can copy and paste,
    > which demonstrates your error.


    Here is part of it, I think that this is enough to be relevent


    #!/usr/bin/perl

    use strict;
    use ........... code removed ............

    my
    ($_RH_users_in_queue,$_RA_user_report_queue,$array_item,$keys,$start_date,
    $end_date);
    my ($_total_tickets,%_total_tickets, $i, $j, %_RH_users_in_queue,
    $_user_resolved, $teamreport, @teamreport, $_norm_tickets);

    .............. code removed ..............

    foreach $i ('queue01','queue02','queue03' )
    {
    $_total_tickets = $query->total_tickets_queue($dbh,
    $query->param(-name=>"$i"), $start_date, $end_date);
    if ( ( $query->param(-name=>"$i") == 0 )
    || $_total_tickets == 0 ) { last }
    $_RH_users_in_queue =
    $query->users_in_queue($dbh,$query->param(-name=>"$i"));
    $_RA_user_report_queue = $query->user_report_queue_resolved($dbh,
    $query->param(-name=>"$i"), $_RH_users_in_queue, $start_date,
    $end_date);
    foreach $j (keys %$_RH_users_in_queue)
    {
    my %matrix;
    $matrix{id} = $j;
    $matrix{name} = $_RH_users_in_queue->{$j};
    $matrix{queue} = $query->param(-name=>"$i");
    $matrix{queue_total} = $_total_tickets;
    $matrix{tickets} =
    $query->user_tickets_resolved($dbh,$matrix{queue},$matrix{id},$start_date,$end_date);
    $matrix{norm_tickets} = ( $matrix{tickets} / $_total_tickets ) *
    100;
    push(@teamreport ,\%matrix);

    }

    }


    #my @teamreport_sorted = sort { $a{norm_tickets} <=> $b{norm_tickets}
    } @teamreport;

    my @teamreport_sorted = sort { ($a->{norm_tickets}) <=>
    ($b->{norm_tickets}) } @teamreport;

    @teamreport_sorted when printed is unsorted.

    thanks,

    fahd
     
    , Oct 6, 2005
    #3
  4. writes:
    >> Please post a short but *complete* program that we can copy and paste,
    >> which demonstrates your error.

    >
    > Here is part of it, I think that this is enough to be relevent


    I don't mean to be rude, but Paul clearly asked for something that is
    short (about 20 lines is reasonably considered short), and most
    importantly, cut-and-pasteable.

    Here's what something like that might look like:

    #!/usr/bin/perl
    use warnings;
    use strict;

    my @unsorted = ( { id => 03, name => "hi", count=> 200 },
    { id => 01, name => "hi", count=> 100 },
    { id => 02, name => "hi", count=> 150 } );

    my @sorted = sort { $a->{count} <=> $b->{count} } @unsorted;

    print "id: [$_->{id}] name: [$_->{name}], count: [$_->{count}]\n" for @sorted;
    __END__

    This gives me:

    id: [1] name: [hi], count: [100]
    id: [2] name: [hi], count: [150]
    id: [3] name: [hi], count: [200]

    Observe the following characteristics, and how they differ from what
    you offered:

    1) My code is very short. It's easy to read. 20 lines is about the
    maximum we recommend that people post, because longer than that,
    code gets much harder to read.

    Your code is about twice that long, and includes a lot of
    extraneous information that a reader has to read and understand and
    then decide if it's meaningful or not.

    2) My code only contains the very bare minimum required to display the
    problem (or in this case, lack of problem :).

    Your code contains about 30 lines of code that doesn't actually
    involve your problem; instead, it's a loop that iterates over data
    we don't know anything about to create a structure that we can only
    guess at.

    Since you're not asking us for help in generating your hashrefs,
    it's not relevant to your problem how your hashrefs are created.
    For the purposes of sorting them, all we need is a few examples of
    what they look like, and what your attempt to sort them looks like.

    3) My code is cut-and-pasteable into a file. Including the __END__
    token will allow anybody who accidentally includes a few extra
    lines to run it anyway.

    If your code cannot be cut and pasted, you lose the help a LOT of
    very talented people who don't want to spend the time reading
    through your code and trying to understand it. Code that runs is
    very easy to look at and understand. Code that doesn't requires
    very hard work to understand, and most of us are volunteers and not
    inclined to doing that work.

    4) I used strict (which you did, and good for you for doing so) AND
    warnings. Posting code which uses both probably doubles if not
    triples the number of people willing to help.

    > #!/usr/bin/perl
    >
    > use strict;
    > use ........... code removed ............


    This doesn't compile. That's why our posting guidelines (which are
    posted on this newsgroup at least twice a week) specify to only post
    code which is cut and pasted; that removes the possibility of typos
    causing problems.

    > my
    > ($_RH_users_in_queue,$_RA_user_report_queue,$array_item,$keys,$start_date,
    > $end_date);
    > my ($_total_tickets,%_total_tickets, $i, $j, %_RH_users_in_queue,
    > $_user_resolved, $teamreport, @teamreport, $_norm_tickets);


    We don't need all this information to solve your problem.

    > ............. code removed ..............
    >
    > foreach $i ('queue01','queue02','queue03' )
    > {
    > $_total_tickets = $query->total_tickets_queue($dbh,
    > $query->param(-name=>"$i"), $start_date, $end_date);
    > if ( ( $query->param(-name=>"$i") == 0 )
    > || $_total_tickets == 0 ) { last }
    > $_RH_users_in_queue =
    > $query->users_in_queue($dbh,$query->param(-name=>"$i"));
    > $_RA_user_report_queue = $query->user_report_queue_resolved($dbh,
    > $query->param(-name=>"$i"), $_RH_users_in_queue, $start_date,
    > $end_date);
    > foreach $j (keys %$_RH_users_in_queue)
    > {
    > my %matrix;
    > $matrix{id} = $j;
    > $matrix{name} = $_RH_users_in_queue->{$j};
    > $matrix{queue} = $query->param(-name=>"$i");
    > $matrix{queue_total} = $_total_tickets;
    > $matrix{tickets} =
    > $query->user_tickets_resolved($dbh,$matrix{queue},$matrix{id},$start_date,$end_date);
    > $matrix{norm_tickets} = ( $matrix{tickets} / $_total_tickets ) *
    > 100;
    > push(@teamreport ,\%matrix);
    >
    > }
    >
    > }


    All this code does is, it seems, build up a list of hashrefs.
    Instead, you could just show us an example list, maybe three or four
    items long. We just need enough information to know what you're
    sorting, and what it looks like.

    > #my @teamreport_sorted = sort { $a{norm_tickets} <=> $b{norm_tickets}
    > } @teamreport;


    This is a little confusing. I'd leave it out next time.

    > my @teamreport_sorted = sort { ($a->{norm_tickets}) <=>
    > ($b->{norm_tickets}) } @teamreport;


    This is the meat of the sort, and as far as I can tell, it's correct.
    The parenthesis are unnecessary, though, and I'd remove them for
    clarity:

    my @teamreport_sorted = sort { $a->{norm_tickets} <=> $b->{norm_tickets} } @teamreport;

    > @teamreport_sorted when printed is unsorted.


    Please show us exactly what it looks like before, and exactly what it
    looks like after. And no, this is NOT a request for every single one
    of your 2,000 hashrefs; just give us a few, and show how you print
    them out before, and how you print them out after; reduce the problem
    to its barest possible essentials.

    This is not, repeat NOT intended as a flame or rip on your skills.
    I'm trying to help you help yourself. If you give us an example that
    follows all 4 of the criteria I delineated above, you'll have a very
    fast answer that is very high quality. And, better yet, in the
    process of stripping things down into the smallest possible example,
    you may even figure out the problem on your own, which is even better.

    -=Eric
     
    Eric Schwartz, Oct 6, 2005
    #4
  5. Guest

    All very valid point Eric,

    Thanks, I'll will do so in the future,

    fahd
     
    , Oct 6, 2005
    #5
  6. Paul Lalli Guest

    wrote:
    > > Please post a short but *complete* program that we can copy and paste,
    > > which demonstrates your error.

    >
    > Here is part of it, I think that this is enough to be relevent


    .... You don't see any contradiction between what I just asked for and
    what you gave? If you don't want to follow my request geared towards
    helping you help us help you, why should I bother attempting to help
    you at all?

    Paul Lalli
     
    Paul Lalli, Oct 6, 2005
    #6
  7. Guest

    fahdsul, this could be your problem

    %matrix = ();
    push(@teamreport ,\%matrix);

    is not the same as

    $matrix = {};
    push(@teamreport ,$matrix);


    try:
    my @teamreport_sorted = sort { ${$a}{norm_tickets} <=>
    ${$b}{norm_tickets} } @teamreport;
     
    , Oct 8, 2005
    #7
  8. Guest

    wrote:
    > fahdsul, this could be your problem
    >
    > %matrix = ();
    > push(@teamreport ,\%matrix);
    >
    > is not the same as
    >
    > $matrix = {};
    > push(@teamreport ,$matrix);
    >
    >
    > try:
    > my @teamreport_sorted = sort { ${$a}{norm_tickets} <=>
    > ${$b}{norm_tickets} } @teamreport;


    Test:
    use strict;
    use warnings;
    use sort 'stable';

    my @teamreport = ();
    for (my $i = 0; $i < 4; $i++) {
    my %matrix = ();
    $matrix{'name'} = "n$i";
    $matrix{'date'} = "d$i";
    $matrix{'quantity'} = 50-(2*$i);
    $matrix{'nothing'} = 'nothing';
    push(@teamreport ,\%matrix);
    }
    my @teamreport_sorted = sort { ${$a}{'quantity'} <=> ${$b}{'quantity'}
    } @teamreport;

    for (@teamreport) {
    print "name:\t${$_}{'name'}\tquantity:\t${$_}{'quantity'}\n";
    }

    print "======================\n";

    for (@teamreport_sorted) {
    print "name:\t${$_}{'name'}\tquantity:\t${$_}{'quantity'}\n";
    }

    '
    D:\Eraser\esp>perl zzz.pl
    name: n0 quantity: 50
    name: n1 quantity: 48
    name: n2 quantity: 46
    name: n3 quantity: 44
    ======================
    name: n3 quantity: 44
    name: n2 quantity: 46
    name: n1 quantity: 48
    name: n0 quantity: 50

    __END__

    If however, %matrix were the same scope as @teamsport, only
    each item in @teamsport references would all be the same
    referencing last values asingned to %matrix.
     
    , Oct 8, 2005
    #8
  9. Guest

    On 7 Oct 2005 17:29:43 -0700, "" <>
    wrote:

    >
    > wrote:
    >> fahdsul, this could be your problem
    >>
    >> %matrix = ();
    >> push(@teamreport ,\%matrix);
    >>
    >> is not the same as
    >>
    >> $matrix = {};
    >> push(@teamreport ,$matrix);
    >>
    >>
    >> try:
    >> my @teamreport_sorted = sort { ${$a}{norm_tickets} <=>
    >> ${$b}{norm_tickets} } @teamreport;

    >
    >Test:
    >use strict;
    >use warnings;
    >use sort 'stable';
    >
    >my @teamreport = ();
    >for (my $i = 0; $i < 4; $i++) {
    > my %matrix = ();
    > $matrix{'name'} = "n$i";
    > $matrix{'date'} = "d$i";
    > $matrix{'quantity'} = 50-(2*$i);
    > $matrix{'nothing'} = 'nothing';
    > push(@teamreport ,\%matrix);
    >}
    >my @teamreport_sorted = sort { ${$a}{'quantity'} <=> ${$b}{'quantity'}
    >} @teamreport;
    >
    >for (@teamreport) {
    > print "name:\t${$_}{'name'}\tquantity:\t${$_}{'quantity'}\n";
    >}
    >
    >print "======================\n";
    >
    >for (@teamreport_sorted) {
    > print "name:\t${$_}{'name'}\tquantity:\t${$_}{'quantity'}\n";
    >}
    >
    >'
    >D:\Eraser\esp>perl zzz.pl
    >name: n0 quantity: 50
    >name: n1 quantity: 48
    >name: n2 quantity: 46
    >name: n3 quantity: 44
    >======================
    >name: n3 quantity: 44
    >name: n2 quantity: 46
    >name: n1 quantity: 48
    >name: n0 quantity: 50
    >
    >__END__
    >
    >If however, %matrix were the same scope as @teamsport, only
    >each item in @teamsport references would all be the same
    >referencing last values asingned to %matrix.


    use strict;
    use warnings;
    use sort 'stable';

    my @teamreport = ();
    for (my $i = 0; $i < 4; $i++) {
    my $matrix = {};
    $matrix->{'name'} = "n$i";
    $matrix->{'date'} = "d$i";
    $matrix->{'quantity'} = 50-(2*$i);
    $matrix->{'nothing'} = 'nothing';
    push(@teamreport ,$matrix);
    }
    my @teamreport_sorted = sort { $a->{'quantity'} <=> $b->{'quantity'}
    } @teamreport;

    for (@teamreport) {
    print "name:\t$_->{'name'}\tquantity:\t$_->{'quantity'}\n";
    }

    print "======================\n";

    for (@teamreport_sorted) {
    print "name:\t$_->{'name'}\tquantity:\t$_->{'quantity'}\n";
    }

    __END__

    name: n0 quantity: 50
    name: n1 quantity: 48
    name: n2 quantity: 46
    name: n3 quantity: 44
    ======================
    name: n3 quantity: 44
    name: n2 quantity: 46
    name: n1 quantity: 48
    name: n0 quantity: 50

    I would imagine this is probably a better way
     
    , Oct 8, 2005
    #9
  10. Guest

    On Thu, 06 Oct 2005 14:50:40 -0600, Eric Schwartz <>
    wrote:

    > writes:
    >>> Please post a short but *complete* program that we can copy and paste,
    >>> which demonstrates your error.

    >>
    >> Here is part of it, I think that this is enough to be relevent

    >
    >I don't mean to be rude, but Paul clearly asked for something that is
    >short (about 20 lines is reasonably considered short), and most
    >importantly, cut-and-pasteable.
    >
    >Here's what something like that might look like:
    >
    >#!/usr/bin/perl
    >use warnings;
    >use strict;
    >
    >my @unsorted = ( { id => 03, name => "hi", count=> 200 },
    > { id => 01, name => "hi", count=> 100 },
    > { id => 02, name => "hi", count=> 150 } );
    >
    >my @sorted = sort { $a->{count} <=> $b->{count} } @unsorted;
    >
    >print "id: [$_->{id}] name: [$_->{name}], count: [$_->{count}]\n" for @sorted;
    >__END__
    >
    >This gives me:
    >
    >id: [1] name: [hi], count: [100]
    >id: [2] name: [hi], count: [150]
    >id: [3] name: [hi], count: [200]
    >

    Yes yours work Eric because you use anonymous hash array reference.
    However, if you glanced at the OP's code you would have noticed
    he used a reference to a hash array, which was probobaly his
    extreme desire to make this work after hours of head bashing.

    Maybe you should pause to consider posters desire to make his/her
    code work before you go into acedemia attack mode on style, context
    and construct...

    his:
    %matrix = ('key' => '');
    push(@teamreport ,\%matrix);
    ${$teamreport[0]}{key} = 'value';

    is not the same as

    yours:
    $matrix = {'key' => ''};
    push(@teamreport ,$matrix);
    $teamreport[0]->{key} = 'value';


    >Observe the following characteristics, and how they differ from what
    >you offered:
    >
    >1) My code is very short. It's easy to read. 20 lines is about the
    > maximum we recommend that people post, because longer than that,
    > code gets much harder to read.
    >
    > Your code is about twice that long, and includes a lot of
    > extraneous information that a reader has to read and understand and
    > then decide if it's meaningful or not.
    >
    >2) My code only contains the very bare minimum required to display the
    > problem (or in this case, lack of problem :).
    >
    > Your code contains about 30 lines of code that doesn't actually
    > involve your problem; instead, it's a loop that iterates over data
    > we don't know anything about to create a structure that we can only
    > guess at.
    >
    > Since you're not asking us for help in generating your hashrefs,
    > it's not relevant to your problem how your hashrefs are created.
    > For the purposes of sorting them, all we need is a few examples of
    > what they look like, and what your attempt to sort them looks like.
    >
    >3) My code is cut-and-pasteable into a file. Including the __END__
    > token will allow anybody who accidentally includes a few extra
    > lines to run it anyway.
    >
    > If your code cannot be cut and pasted, you lose the help a LOT of
    > very talented people who don't want to spend the time reading
    > through your code and trying to understand it. Code that runs is
    > very easy to look at and understand. Code that doesn't requires
    > very hard work to understand, and most of us are volunteers and not
    > inclined to doing that work.
    >
    >4) I used strict (which you did, and good for you for doing so) AND
    > warnings. Posting code which uses both probably doubles if not
    > triples the number of people willing to help.
    >
    >> #!/usr/bin/perl
    >>
    >> use strict;
    >> use ........... code removed ............

    >
    >This doesn't compile. That's why our posting guidelines (which are
    >posted on this newsgroup at least twice a week) specify to only post
    >code which is cut and pasted; that removes the possibility of typos
    >causing problems.
    >
    >> my
    >> ($_RH_users_in_queue,$_RA_user_report_queue,$array_item,$keys,$start_date,
    >> $end_date);
    >> my ($_total_tickets,%_total_tickets, $i, $j, %_RH_users_in_queue,
    >> $_user_resolved, $teamreport, @teamreport, $_norm_tickets);

    >
    >We don't need all this information to solve your problem.
    >
    >> ............. code removed ..............
    >>
    >> foreach $i ('queue01','queue02','queue03' )
    >> {
    >> $_total_tickets = $query->total_tickets_queue($dbh,
    >> $query->param(-name=>"$i"), $start_date, $end_date);
    >> if ( ( $query->param(-name=>"$i") == 0 )
    >> || $_total_tickets == 0 ) { last }
    >> $_RH_users_in_queue =
    >> $query->users_in_queue($dbh,$query->param(-name=>"$i"));
    >> $_RA_user_report_queue = $query->user_report_queue_resolved($dbh,
    >> $query->param(-name=>"$i"), $_RH_users_in_queue, $start_date,
    >> $end_date);
    >> foreach $j (keys %$_RH_users_in_queue)
    >> {
    >> my %matrix;
    >> $matrix{id} = $j;
    >> $matrix{name} = $_RH_users_in_queue->{$j};
    >> $matrix{queue} = $query->param(-name=>"$i");
    >> $matrix{queue_total} = $_total_tickets;
    >> $matrix{tickets} =
    >> $query->user_tickets_resolved($dbh,$matrix{queue},$matrix{id},$start_date,$end_date);
    >> $matrix{norm_tickets} = ( $matrix{tickets} / $_total_tickets ) *
    >> 100;
    >> push(@teamreport ,\%matrix);
    >>
    >> }
    >>
    >> }

    >
    >All this code does is, it seems, build up a list of hashrefs.
    >Instead, you could just show us an example list, maybe three or four
    >items long. We just need enough information to know what you're
    >sorting, and what it looks like.
    >
    >> #my @teamreport_sorted = sort { $a{norm_tickets} <=> $b{norm_tickets}
    >> } @teamreport;

    >
    >This is a little confusing. I'd leave it out next time.
    >
    >> my @teamreport_sorted = sort { ($a->{norm_tickets}) <=>
    >> ($b->{norm_tickets}) } @teamreport;

    >
    >This is the meat of the sort, and as far as I can tell, it's correct.
    >The parenthesis are unnecessary, though, and I'd remove them for
    >clarity:
    >
    >my @teamreport_sorted = sort { $a->{norm_tickets} <=> $b->{norm_tickets} } @teamreport;
    >
    >> @teamreport_sorted when printed is unsorted.

    >
    >Please show us exactly what it looks like before, and exactly what it
    >looks like after. And no, this is NOT a request for every single one
    >of your 2,000 hashrefs; just give us a few, and show how you print
    >them out before, and how you print them out after; reduce the problem
    >to its barest possible essentials.
    >
    >This is not, repeat NOT intended as a flame or rip on your skills.
    >I'm trying to help you help yourself. If you give us an example that
    >follows all 4 of the criteria I delineated above, you'll have a very
    >fast answer that is very high quality. And, better yet, in the
    >process of stripping things down into the smallest possible example,
    >you may even figure out the problem on your own, which is even better.
    >
    >-=Eric
     
    , Oct 8, 2005
    #10
  11. Matt Garrish Guest

    <> wrote in message
    news:...
    >
    > use strict;
    > use warnings;
    > use sort 'stable';
    >
    > my @teamreport = ();
    > for (my $i = 0; $i < 4; $i++) {
    > my $matrix = {};
    > $matrix->{'name'} = "n$i";
    > $matrix->{'date'} = "d$i";
    > $matrix->{'quantity'} = 50-(2*$i);
    > $matrix->{'nothing'} = 'nothing';
    > push(@teamreport ,$matrix);
    > }
    > my @teamreport_sorted = sort { $a->{'quantity'} <=> $b->{'quantity'}
    > } @teamreport;
    >
    > for (@teamreport) {
    > print "name:\t$_->{'name'}\tquantity:\t$_->{'quantity'}\n";
    > }
    >
    > print "======================\n";
    >


    [pet peeve]

    print '='x22, "\n";

    Matt
     
    Matt Garrish, Oct 8, 2005
    #11
  12. writes:
    > Yes yours work Eric because you use anonymous hash array reference.
    > However, if you glanced at the OP's code you would have noticed
    > he used a reference to a hash array, which was probobaly his
    > extreme desire to make this work after hours of head bashing.
    >
    > Maybe you should pause to consider posters desire to make his/her
    > code work before you go into acedemia attack mode on style, context
    > and construct...


    Maybe if the poster had actually posted a short, executable example,
    I'd have been able to more easily read it, which was the point in the
    first place. My critique was hardly "academia" (sic); it was to the
    point. I think it will help the OP far more to learn how to ask for
    help in the best way possible, than to spend 3 times as long to try to
    understand his example.

    And for your reference, the OP himself admitted that his example was
    difficult to follow, and thanked me for my advice. Take that for what
    you will.

    -=Eric
     
    Eric Schwartz, Oct 10, 2005
    #12
    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. Navin
    Replies:
    1
    Views:
    710
    Ken Schaefer
    Sep 9, 2003
  2. rp
    Replies:
    1
    Views:
    543
    red floyd
    Nov 10, 2011
  3. Srijayanth Sridhar
    Replies:
    19
    Views:
    629
    David A. Black
    Jul 2, 2008
  4. llama

    sort array of hash references

    llama, Jul 29, 2003, in forum: Perl Misc
    Replies:
    1
    Views:
    107
    llama
    Jul 29, 2003
  5. Arvin Portlock
    Replies:
    6
    Views:
    142
    Arvin Portlock
    Sep 2, 2005
Loading...

Share This Page