Sorting array of hash references

Discussion in 'Perl Misc' started by alwaysonnet, Oct 26, 2006.

  1. alwaysonnet

    alwaysonnet Guest

    hi all,

    I've got an array of hash-references as following. ( i've represented
    hash-references as a table below)


    Type A/C No Status(active/inactive)

    Prefund 12345 Y
    Prefund 45678 N
    Receipt 78878 N
    Receipt 32365 Y
    Payment 56546 N
    Payment 23456 N
    Payment 34093 Y

    I want to display all the active accounts (status with "Y") before
    inactive accounts along with preserving the order by type ie., Prefund
    should come first before Receipt and Payment along the order.

    I've got the code which i've hard-coded the account type(Payment) and
    then sorting according to their status.

    foreach my $label(@accts) {
    if ($label->{'batype'} eq "Payment") {
    push(@acct_pay,$label);
    }
    }
    foreach $x(@acct_pay) {
    @sorted = sort { $b->{'baactive'} cmp $a->{'baactive'} } @acct_pay;
    }

    Is there any way of how to achieve this by sorting according to status
    by preserving the account type order.

    Thanks a ton,
    Raj
     
    alwaysonnet, Oct 26, 2006
    #1
    1. Advertising

  2. alwaysonnet

    -berlin.de Guest

    alwaysonnet <> wrote in comp.lang.perl.misc:
    > hi all,
    >
    > I've got an array of hash-references as following. ( i've represented
    > hash-references as a table below)


    It would have been *much* better to present Perl code that produces
    the array of hashes instead of a table that leaves us guessing how
    your data relate to your code.

    > Type A/C No Status(active/inactive)
    >
    > Prefund 12345 Y
    > Prefund 45678 N
    > Receipt 78878 N
    > Receipt 32365 Y
    > Payment 56546 N
    > Payment 23456 N
    > Payment 34093 Y
    >
    > I want to display all the active accounts (status with "Y") before
    > inactive accounts along with preserving the order by type ie., Prefund
    > should come first before Receipt and Payment along the order.


    Unless you're running a rather old version of Perl, Perl's sort() is
    stable, meaning the original order is preserved when elements compare
    equal. If you simply sort by status the result should be what you
    want.

    > I've got the code which i've hard-coded the account type(Payment) and
    > then sorting according to their status.
    >
    > foreach my $label(@accts) {
    > if ($label->{'batype'} eq "Payment") {


    Is "batype" what appears in the column "Type"? Is "baactive" what
    appears in column "Status(active/inactive)"? Please make explicit
    what is what, don't let your readers guess.

    > push(@acct_pay,$label);
    > }
    > }
    > foreach $x(@acct_pay) {
    > @sorted = sort { $b->{'baactive'} cmp $a->{'baactive'} } @acct_pay;
    > }
    >
    > Is there any way of how to achieve this by sorting according to status
    > by preserving the account type order.


    That will only show the three "Payment" records. What does it have to
    do with your question?

    Anno
     
    -berlin.de, Oct 26, 2006
    #2
    1. Advertising

  3. alwaysonnet

    alwaysonnet Guest

    hi ,

    "batype" refers to column "Type" , "baactive" refers to column
    "Status(active/inactive)"?

    anno, You're correct that the code will show only 3 records of
    "Payment" type as I have put a condition like "if ($label->{'batype'}
    eq "Payment") ".

    I need to preserve the actual order of "Type" but for each "Type" i
    need to sort with their active accounts.

    Raj


    -berlin.de wrote:
    > alwaysonnet <> wrote in comp.lang.perl.misc:
    > > hi all,
    > >
    > > I've got an array of hash-references as following. ( i've represented
    > > hash-references as a table below)

    >
    > It would have been *much* better to present Perl code that produces
    > the array of hashes instead of a table that leaves us guessing how
    > your data relate to your code.
    >
    > > Type A/C No Status(active/inactive)
    > >
    > > Prefund 12345 Y
    > > Prefund 45678 N
    > > Receipt 78878 N
    > > Receipt 32365 Y
    > > Payment 56546 N
    > > Payment 23456 N
    > > Payment 34093 Y
    > >
    > > I want to display all the active accounts (status with "Y") before
    > > inactive accounts along with preserving the order by type ie., Prefund
    > > should come first before Receipt and Payment along the order.

    >
    > Unless you're running a rather old version of Perl, Perl's sort() is
    > stable, meaning the original order is preserved when elements compare
    > equal. If you simply sort by status the result should be what you
    > want.
    >
    > > I've got the code which i've hard-coded the account type(Payment) and
    > > then sorting according to their status.
    > >
    > > foreach my $label(@accts) {
    > > if ($label->{'batype'} eq "Payment") {

    >
    > Is "batype" what appears in the column "Type"? Is "baactive" what
    > appears in column "Status(active/inactive)"? Please make explicit
    > what is what, don't let your readers guess.
    >
    > > push(@acct_pay,$label);
    > > }
    > > }
    > > foreach $x(@acct_pay) {
    > > @sorted = sort { $b->{'baactive'} cmp $a->{'baactive'} } @acct_pay;
    > > }
    > >
    > > Is there any way of how to achieve this by sorting according to status
    > > by preserving the account type order.

    >
    > That will only show the three "Payment" records. What does it have to
    > do with your question?
    >
    > Anno
     
    alwaysonnet, Oct 26, 2006
    #3
  4. alwaysonnet

    -berlin.de Guest

    alwaysonnet <> wrote in comp.lang.perl.misc:
    > hi ,
    >
    > "batype" refers to column "Type" , "baactive" refers to column
    > "Status(active/inactive)"?
    >
    > anno, You're correct that the code will show only 3 records of
    > "Payment" type as I have put a condition like "if ($label->{'batype'}
    > eq "Payment") ".
    >
    > I need to preserve the actual order of "Type" but for each "Type" i
    > need to sort with their active accounts.


    [Tofu snipped. Don't do that]

    So just sort by "baactive", your records are already sorted by "batype".
    As I said in my previous reply, Perl's sort is stable unless you have
    an old version of Perl.

    Anno
     
    -berlin.de, Oct 26, 2006
    #4
  5. alwaysonnet <> wrote:


    > I've got an array of hash-references as following.



    If you say so, but those are some mighty cumbersome keys...


    > ( i've represented
    > hash-references as a table below)



    Why have you done that rather than representing them in real Perl
    code that an answerer could use to test any potential answers?

    If you make the answerer do that extra work, they are likely to move on
    to helping some other poster who has taken the time to make it
    easier for them to give an accurate answer.

    Have you seen the Posting Guidelines that are posted here frequently?


    [ snip the table ]


    > I want to display all the active accounts (status with "Y") before
    > inactive accounts along with preserving the order by type ie., Prefund

    ^^^^^^^^^^^^^^^^^^^^
    > should come first before Receipt and Payment along the order.



    Recent perls have a "stable" sort, so you should get that by default.


    > if ($label->{'batype'} eq "Payment") {

    ^^^^^^

    That is not the key that you said in the table. Which is it?

    Precision is important in programming...


    > Is there any way of how to achieve this by sorting according to status
    > by preserving the account type order.



    Yes, and it is a plain old everyday sort that you should have been
    able to get simply by reading the docs about sorting...


    ----------------------------
    #!/usr/bin/perl
    use warnings;
    use strict;
    use Data::Dumper;

    my @records = (
    { 'Type' => 'Prefund', 'A/C No' => 12345, 'Status(active/inactive)' => 'Y' },
    { 'Type' => 'Prefund', 'A/C No' => 45678, 'Status(active/inactive)' => 'N' },
    { 'Type' => 'Receipt', 'A/C No' => 78878, 'Status(active/inactive)' => 'N' },
    { 'Type' => 'Receipt', 'A/C No' => 32365, 'Status(active/inactive)' => 'Y' },
    { 'Type' => 'Payment', 'A/C No' => 56546, 'Status(active/inactive)' => 'N' },
    { 'Type' => 'Payment', 'A/C No' => 23456, 'Status(active/inactive)' => 'N' },
    { 'Type' => 'Payment', 'A/C No' => 34093, 'Status(active/inactive)' => 'Y' },
    );

    my @sorted = sort { $b->{'Status(active/inactive)'} cmp
    $a->{'Status(active/inactive)'}
    } @records;

    print Dumper \@sorted;
    ----------------------------


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Oct 26, 2006
    #5
  6. alwaysonnet

    Guest

    -berlin.de wrote:
    > alwaysonnet <> wrote in comp.lang.perl.misc:
    > > hi ,
    > >
    > > "batype" refers to column "Type" , "baactive" refers to column
    > > "Status(active/inactive)"?
    > >
    > > anno, You're correct that the code will show only 3 records of
    > > "Payment" type as I have put a condition like "if ($label->{'batype'}
    > > eq "Payment") ".
    > >
    > > I need to preserve the actual order of "Type" but for each "Type" i
    > > need to sort with their active accounts.

    >
    > [Tofu snipped. Don't do that]
    >
    > So just sort by "baactive", your records are already sorted by "batype".
    > As I said in my previous reply, Perl's sort is stable unless you have
    > an old version of Perl.


    But that isn't necessarily what he wants. Maybe He wants them sorted
    first by type, then by status. Not first by status, but then by type,
    which is what stable sort would give him.


    my %type_order = qw/Prefund 1 Receipt 2 Payment 3/;

    @sorted = sort { $type_order{$a->{'type'}} <=> $type_order{$b->{'type'}}
    ||
    $b->{'baactive'} cmp $a->{'baactive'}
    } @acct_pay;

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Oct 26, 2006
    #6
  7. alwaysonnet

    -berlin.de Guest

    <> wrote in comp.lang.perl.misc:
    > -berlin.de wrote:
    > > alwaysonnet <> wrote in comp.lang.perl.misc:
    > > > hi ,
    > > >
    > > > "batype" refers to column "Type" , "baactive" refers to column
    > > > "Status(active/inactive)"?
    > > >
    > > > anno, You're correct that the code will show only 3 records of
    > > > "Payment" type as I have put a condition like "if ($label->{'batype'}
    > > > eq "Payment") ".
    > > >
    > > > I need to preserve the actual order of "Type" but for each "Type" i
    > > > need to sort with their active accounts.

    > >
    > > [Tofu snipped. Don't do that]
    > >
    > > So just sort by "baactive", your records are already sorted by "batype".
    > > As I said in my previous reply, Perl's sort is stable unless you have
    > > an old version of Perl.

    >
    > But that isn't necessarily what he wants. Maybe He wants them sorted
    > first by type, then by status. Not first by status, but then by type,
    > which is what stable sort would give him.


    I thought of that, but

    I want to display all the active accounts (status with "Y") before
    inactive accounts...

    doesn't leave much doubt that "status" is the primary key.

    [nicely formatted two-key sort snipped]

    Since the primary key is only two-valued, sort() could be replaced
    with two grep()s (untested):

    @sorted = (
    grep( $_->{ baactive} eq 'Y', @acct_pay),
    grep( $_->{ baactive} eq 'N', @acct_pay),
    );

    Anno
     
    -berlin.de, Oct 26, 2006
    #7
  8. alwaysonnet

    alwaysonnet Guest

    Hi Xho,

    The code snippet you've provided really worked out for me.

    Thanks,
    Raj
     
    alwaysonnet, Oct 27, 2006
    #8
  9. alwaysonnet

    alwaysonnet Guest

    hi,

    my %type_order = qw/Prefund 1 Receipt 2 Payment 3/;

    my @records = (
    { 'Type' => 'Prefund', 'A/C No' => 12345, 'Status(active/inactive)' =>
    'Y' },
    { 'Type' => 'Prefund', 'A/C No' => 45678, 'Status(active/inactive)' =>
    'N' },
    { 'Type' => 'Receipt', 'A/C No' => 78878, 'Status(active/inactive)' =>
    'N' },
    { 'Type' => 'Payment', 'A/C No' => 88888, 'Status(active/inactive)' =>
    'Y' },
    { 'Type' => 'Receipt', 'A/C No' => 32365, 'Status(active/inactive)' =>
    'Y' },
    { 'Type' => 'Prefund', 'A/C No' => 11111, 'Status(active/inactive)' =>
    'N' },
    { 'Type' => 'Payment', 'A/C No' => 56546, 'Status(active/inactive)' =>
    'N' },
    { 'Type' => 'Payment', 'A/C No' => 23456, 'Status(active/inactive)' =>
    'N' },
    { 'Type' => 'Payment', 'A/C No' => 34093, 'Status(active/inactive)' =>
    'Y' },
    );

    my @sorted = sort { $type_order{$a->{'Type'}} <=>
    $type_order{$b->{'Type'}}
    ||
    $b->{'Status(active/inactive)'} cmp
    $a->{'Status(active/inactive)'}

    } @records;

    which is exactly displaying the active records for a particular account
    type.

    Can further sorting on 'A/C No' so that all the active/inactive records
    for a particular account type should be displayed in sorted order.

    Ex: In this case for the type "Prefund" a/c no's 45678 and 11111 are
    not sorted where their active/inactive status are "N".

    Thanks,
    Raj
     
    alwaysonnet, Oct 30, 2006
    #9
  10. alwaysonnet <> wrote:
    > hi,
    >
    > my %type_order = qw/Prefund 1 Receipt 2 Payment 3/;
    >
    > my @records = (
    > { 'Type' => 'Prefund', 'A/C No' => 12345, 'Status(active/inactive)' =>
    > 'Y' },



    That is a horrid choice of Status key.

    Q: is the status active or inactive?

    A: yes

    huh??

    'Status active' => 'Y'

    or

    'Status' => 'active'

    would be much better.


    > { 'Type' => 'Prefund', 'A/C No' => 45678, 'Status(active/inactive)' =>
    > 'N' },
    > { 'Type' => 'Receipt', 'A/C No' => 78878, 'Status(active/inactive)' =>
    > 'N' },
    > { 'Type' => 'Payment', 'A/C No' => 88888, 'Status(active/inactive)' =>
    > 'Y' },
    > { 'Type' => 'Receipt', 'A/C No' => 32365, 'Status(active/inactive)' =>
    > 'Y' },
    > { 'Type' => 'Prefund', 'A/C No' => 11111, 'Status(active/inactive)' =>
    > 'N' },
    > { 'Type' => 'Payment', 'A/C No' => 56546, 'Status(active/inactive)' =>
    > 'N' },
    > { 'Type' => 'Payment', 'A/C No' => 23456, 'Status(active/inactive)' =>
    > 'N' },
    > { 'Type' => 'Payment', 'A/C No' => 34093, 'Status(active/inactive)' =>
    > 'Y' },
    > );
    >
    > my @sorted = sort { $type_order{$a->{'Type'}} <=>
    > $type_order{$b->{'Type'}}
    > ||
    > $b->{'Status(active/inactive)'} cmp
    > $a->{'Status(active/inactive)'}
    >
    > } @records;
    >
    > which is exactly displaying the active records for a particular account
    > type.
    >
    > Can further sorting on 'A/C No' so that all the active/inactive records
    > for a particular account type should be displayed in sorted order.



    Yes.

    What happened when you tried it?

    If you show us your broken code we will help you fix it.


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Oct 30, 2006
    #10
  11. alwaysonnet

    alwaysonnet Guest

    Sorry if I'm putting more no of keys. This is my final requirement.

    For a particular "Type", if two or more records are having the same
    status and same currency then sort them according to their a/c no's
    where a/c no is a unique.

    Here , Data is displayed for every "Type" in sorted order of their
    "ZCurrency" based on their "Status".

    for ex : For "Type", Payment where A/C Status are "Y" , with a/c no's
    2247,2244 ,records are displayed based on Currencies "AUS","BEL".

    Similarly, for the "Type", Payment where A/C Status are "N" , with a/c
    no's 56546,44444 are having the same currency "EUR".

    So my requirement is that I want these two records with a/c no's
    56546,44444 in sorted order.

    #!/usr/bin/perl
    use Data::Dumper;

    my %type_order = qw/Prefund 1 Receipt 2 Payment 3/;

    my @records = (
    {'Type'=>'Prefund' , 'A/C No'=>12345 , 'Status active'=>'Y',
    'ZCurrency' =>'GBP'},
    {'Type'=>'Prefund' , 'A/C No'=>45678 , 'Status active'=>'N',
    'ZCurrency' =>'SEK'},
    {'Type'=>'Prefund' , 'A/C No'=>33333 , 'Status active'=>'N',
    'ZCurrency' =>'ZAR'},
    {'Type'=>'Receipt' , 'A/C No'=>32365 , 'Status active'=>'Y',
    'ZCurrency' =>'EUR'},
    {'Type'=>'Receipt' , 'A/C No'=>78878 , 'Status active'=>'N',
    'ZCurrency' =>'AIR'},
    {'Type'=>'Receipt' , 'A/C No'=>64237 , 'Status active'=>'N',
    'ZCurrency' =>'GBP'},
    {'Type'=>'Payment' , 'A/C No'=>2247 , 'Status active'=>'Y',
    'ZCurrency' =>'AUS'},
    {'Type'=>'Payment' , 'A/C No'=>2244 , 'Status active'=>'Y',
    'ZCurrency' =>'BEL'},
    {'Type'=>'Payment' , 'A/C No'=>56546 , 'Status active'=>'N',
    'ZCurrency' =>'EUR'},
    {'Type'=>'Payment' , 'A/C No'=>44444 , 'Status active'=>'N',
    'ZCurrency' =>'EUR'},
    );

    my @sorted = sort { $type_order{$a->{'batype'}} <=>
    $type_order{$b->{'batype'}}
    ||
    $b->{'baactive'} cmp
    $a->{'baactive'}
    ||
    $a->{'banum'} <=> $b->{'banum'}
    ||
    $a->{'bacur'} eq $b->{'bacur'}
    } @records;

    print Dumper \@sorted;

    Thanks a ton.
    Raj
     
    alwaysonnet, Oct 30, 2006
    #11
    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:
    557
    red floyd
    Nov 10, 2011
  2. Anthony Martinez
    Replies:
    4
    Views:
    287
    Robert Klemme
    Jun 11, 2007
  3. Srijayanth Sridhar
    Replies:
    19
    Views:
    644
    David A. Black
    Jul 2, 2008
  4. Arvin Portlock
    Replies:
    6
    Views:
    146
    Arvin Portlock
    Sep 2, 2005
  5. Replies:
    11
    Views:
    198
    Eric Schwartz
    Oct 10, 2005
Loading...

Share This Page