Need to retain the order of array of hash references.

A

alwaysonnet

hi all -- Help needed

I'm trying to sort an array of hash-references based on the "A/C No" by
preserving the "Type" order,'ZCurrency' and 'Status' , where "A/C No"
is unique for every record.

Important Note is that - if Records having same "Type","Status" and
"ZCurrency" have different "A/C No" so sorting them with "A/C No"
doesn't effect the actual order of display.

1) I'm looping through every element, checking current record if
"Type","Status" and "ZCurrency" is equal to previous record. if not,
pushing it to final array.

2) if current record matches with previous record, i'm pushing to
another array and sorting them with the "A/C No". Because, both the
records will have same "Type","Status" and "ZCurrency".

3) By this, I got two arrays @final and @curr ... need to merge them
into one by sorting with "A/C No" and preserving the order with
original but sort with "A/C No" if the records have same
"Type","Status" and "ZCurrency".

Partially working code ---

#!/usr/bin/perl

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

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

foreach $current (@records) {
if ($previous->{'Type'} eq $current->{'Type'} && $previous->{'Status'}
eq $current->{'Status'} && $previous->{'ZCurrency'} eq
$current->{'ZCurrency'}) {
push(@curr,$previous);
push(@curr,$current);
} else {
push(@final,$current);
}
$previous = $current;
}

%seen = ();
foreach $item (@curr) {
push(@uniq, $item) unless $seen{$item}++;
}

@uniq = sort { $type_order{$a->{'Type'}} <=> $type_order{$b->{'Type'}}
||
$a->{'A/C No'} <=> $b->{'A/C No'}

} @uniq;

foreach $x(@uniq) {
print " $x->{'Type'} $x->{'A/C No'} $x->{'Status'}
$x->{'ZCurrency'}\n";
}

I want my final output as

{'Type'=>'Prefund' , 'A/C No'=>12345 , 'Status'=>'Y', 'ZCurrency'
=>'GBP'},
{'Type'=>'Prefund' , 'A/C No'=>33333 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},
{'Type'=>'Prefund' , 'A/C No'=>45678 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},
{'Type'=>'Prefund' , 'A/C No'=>32222 , 'Status'=>'N', 'ZCurrency'
=>'SEK'},
{'Type'=>'Receipt' , 'A/C No'=>32365 , 'Status'=>'Y', 'ZCurrency'
=>'EUR'},
{'Type'=>'Receipt' , 'A/C No'=>32435 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},
{'Type'=>'Receipt' , 'A/C No'=>78878 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},
{'Type'=>'Receipt' , 'A/C No'=>64237 , 'Status'=>'N', 'ZCurrency'
=>'GBP'},
{'Type'=>'Payment' , 'A/C No'=>22476 , 'Status'=>'Y', 'ZCurrency'
=>'AUS'},
{'Type'=>'Payment' , 'A/C No'=>22447 , 'Status'=>'Y', 'ZCurrency'
=>'BEL'},
{'Type'=>'Payment' , 'A/C No'=>43434 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>44444 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>56546 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},

So records to be effected are

{'Type'=>'Prefund' , 'A/C No'=>45678 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},
{'Type'=>'Prefund' , 'A/C No'=>33333 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},

{'Type'=>'Receipt' , 'A/C No'=>78878 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},
{'Type'=>'Receipt' , 'A/C No'=>32435 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},

{'Type'=>'Payment' , 'A/C No'=>56546 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>44444 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>43434 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},

Thanks,
Raj
 
J

Jim Gibson

alwaysonnet said:
hi all -- Help needed

I am afraid I do not understand exactly what it is you are trying to
accomplish. Perhaps you can clarify some of your confusing and
contradictory statements.
I'm trying to sort an array of hash-references based on the "A/C No" by
preserving the "Type" order,'ZCurrency' and 'Status' , where "A/C No"
is unique for every record.

If 'A/C No' values are unique, then you can do a simple sort on 'A/C
No'. There is no need to retain the order, because the order of the
sorted array is completely determined by the values of 'A/C No'.
Unfortunately, your sample output below is NOT sorted by 'A/C No'.
Important Note is that - if Records having same "Type","Status" and
"ZCurrency" have different "A/C No" so sorting them with "A/C No"
doesn't effect the actual order of display.

This sentence doesn't make any sense, and in fact may not be
grammatically correct. Did you mean "if ... then ..." instead of "if
.... so ..."?

If two or more records have the same 'Type', 'Status', and 'ZCurrency'
values and different 'A/C No' values, then sorting them by 'A/C No' can
definitely affect their order in the final result.
1) I'm looping through every element, checking current record if
"Type","Status" and "ZCurrency" is equal to previous record. if not,
pushing it to final array.

You should be using Perl's sort function to sort your records.
2) if current record matches with previous record, i'm pushing to
another array and sorting them with the "A/C No". Because, both the
records will have same "Type","Status" and "ZCurrency".

Are records with the same 'Type', 'Status', and 'ZCurrency' values
always continguous in your set of records?
3) By this, I got two arrays @final and @curr ... need to merge them
into one by sorting with "A/C No" and preserving the order with
original but sort with "A/C No" if the records have same
"Type","Status" and "ZCurrency".

One general technique for preserving order in a sort is to add an
extra, temporary field that contains a sequence number defined however
you wish with unique value for each record. You can then use this field
as your final sort key to be used when the other sort keys are
identical. However, current versions of Perl use an order-preserving
sort algorithm, so if you do your sorting in one step this shouldn't be
necessary.
Partially working code ---

#!/usr/bin/perl

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

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

foreach $current (@records) {
if ($previous->{'Type'} eq $current->{'Type'} && $previous->{'Status'}
eq $current->{'Status'} && $previous->{'ZCurrency'} eq
$current->{'ZCurrency'}) {
push(@curr,$previous);
push(@curr,$current);
} else {
push(@final,$current);
}
$previous = $current;
}

%seen = ();
foreach $item (@curr) {
push(@uniq, $item) unless $seen{$item}++;
}

@uniq = sort { $type_order{$a->{'Type'}} <=> $type_order{$b->{'Type'}}
||
$a->{'A/C No'} <=> $b->{'A/C No'}

} @uniq;

foreach $x(@uniq) {
print " $x->{'Type'} $x->{'A/C No'} $x->{'Status'}
$x->{'ZCurrency'}\n";
}

I want my final output as

{'Type'=>'Prefund' , 'A/C No'=>12345 , 'Status'=>'Y', 'ZCurrency'
=>'GBP'},
{'Type'=>'Prefund' , 'A/C No'=>33333 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},
{'Type'=>'Prefund' , 'A/C No'=>45678 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},
{'Type'=>'Prefund' , 'A/C No'=>32222 , 'Status'=>'N', 'ZCurrency'
=>'SEK'},
{'Type'=>'Receipt' , 'A/C No'=>32365 , 'Status'=>'Y', 'ZCurrency'
=>'EUR'},
{'Type'=>'Receipt' , 'A/C No'=>32435 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},
{'Type'=>'Receipt' , 'A/C No'=>78878 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},
{'Type'=>'Receipt' , 'A/C No'=>64237 , 'Status'=>'N', 'ZCurrency'
=>'GBP'},
{'Type'=>'Payment' , 'A/C No'=>22476 , 'Status'=>'Y', 'ZCurrency'
=>'AUS'},
{'Type'=>'Payment' , 'A/C No'=>22447 , 'Status'=>'Y', 'ZCurrency'
=>'BEL'},
{'Type'=>'Payment' , 'A/C No'=>43434 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>44444 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>56546 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},

It looks like you want to sort by: 1) 'Type', 2) 'Status', 3)
'ZCurrency', and 4) 'A/C No'. Is that correct? Try this (untested):

@sorted = sort { $a->{'Type'} cmp $b->{'Type'} ||
$a->{'Status'} cmp $b->{'Status'} ||
$a->{'ZCurrency'} cmp $b->{'ZCurrency'} ||
$a->{'A/C No'} cmp $b->{'A/C No'} } @records;
So records to be effected are

{'Type'=>'Prefund' , 'A/C No'=>45678 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},
{'Type'=>'Prefund' , 'A/C No'=>33333 , 'Status'=>'Y', 'ZCurrency'
=>'SEK'},

{'Type'=>'Receipt' , 'A/C No'=>78878 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},
{'Type'=>'Receipt' , 'A/C No'=>32435 , 'Status'=>'N', 'ZCurrency'
=>'AIR'},

{'Type'=>'Payment' , 'A/C No'=>56546 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>44444 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},
{'Type'=>'Payment' , 'A/C No'=>43434 , 'Status'=>'N', 'ZCurrency'
=>'EUR'},

You can help us help you by writing a complete, short-as-possible,
working program that demonstrates the problem you are having. In your
case, I would recommend testing with fewer and shorter data records
until you get the sort part working. Something link:

@records = (
{ a => 1, b => 1, c => 1, d => 1 },
{ a => 1, b => 1, c => 1, d => 2 },
{ a => 1, b => 1, c => 1, d => 3 },

(you get the picture, I hope).

Good luck.
 
A

alwaysonnet

May be i'm weak in conveying my requirement... here we go...
If 'A/C No' values are unique, then you can do a simple sort on 'A/C
No'. There is no need to retain the order, because the order of the
sorted array is completely determined by the values of 'A/C No'.
Unfortunately, your sample output below is NOT sorted by 'A/C No'.
If 'A/C No' values are unique, then you can do a simple sort on 'A/C
No'. There is no need to retain the order, because the order of the
sorted array is completely determined by the values of 'A/C No'.
Unfortunately, your sample output below is NOT sorted by 'A/C No'.

'A/C No' is unique for all the records, but the records must be
displayed in contiguous order of prefund,receipt and payment.

For Ex- If there are 3 - Prefund , 4- Receipt and 2- Payment records,
then all the records must be displayed as

Prefund
Prefund
Prefund
Receipt
Receipt
Receipt
Receipt
Payment
Payment

So ,sorting with 'A/C No' will effect the order of "Type" which I dont
want. that's why i declared an hash of type_order.
If two or more records have the same 'Type', 'Status', and 'ZCurrency'
values and different 'A/C No' values, then sorting them by 'A/C No' can
definitely affect their order in the final result.

I agree with you that if two records with same "Type",'Status' and
'ZCurrency' then sorting them with A/C No will definitely effect their
result.
Are records with the same 'Type', 'Status', and 'ZCurrency' values
always continguous in your set of records?

Yes, if records are having same "Type","Status" and "ZCurrency" , they
are always contiguous but their "A/C No" are not in sorted order.

so , my concern is to sort the contigous records having same
"Type","Status" and "ZCurrency" with their "A/C No"'s
It looks like you want to sort by: 1) 'Type', 2) 'Status', 3)
'ZCurrency', and 4) 'A/C No'. Is that correct? Try this (untested):

@sorted = sort { $a->{'Type'} cmp $b->{'Type'} ||
$a->{'Status'} cmp $b->{'Status'} ||
$a->{'ZCurrency'} cmp $b->{'ZCurrency'} ||
$a->{'A/C No'} cmp $b->{'A/C No'} } @records;

You can help us help you by writing a complete, short-as-possible,
working program that demonstrates the problem you are having. In your
case, I would recommend testing with fewer and shorter data records
until you get the sort part working. Something link:

@records = (
{ a => 1, b => 1, c => 1, d => 1 },
{ a => 1, b => 1, c => 1, d => 2 },
{ a => 1, b => 1, c => 1, d => 3 },

(you get the picture, I hope).

Good luck.

Thanks,
Raj
 
A

alwaysonnet

May be i'm weak in conveying my requirement... here we go...

If 'A/C No' values are unique, then you can do a simple sort on 'A/C
No'. There is no need to retain the order, because the order of the
sorted array is completely determined by the values of 'A/C No'.
Unfortunately, your sample output below is NOT sorted by 'A/C No'.

'A/C No' is unique for all the records, but the records must be
displayed in contiguous order of prefund,receipt and payment.

For Ex- If there are 3 - Prefund , 4- Receipt and 2- Payment records,
then all the records must be displayed as

Prefund
Prefund
Prefund
Receipt
Receipt
Receipt
Receipt
Payment
Payment

So ,sorting with 'A/C No' will effect the order of "Type" which I dont
want. that's why i declared an hash of type_order.
If two or more records have the same 'Type', 'Status', and 'ZCurrency'
values and different 'A/C No' values, then sorting them by 'A/C No' can
definitely affect their order in the final result.

I agree with you that if two records with same "Type",'Status' and
'ZCurrency' then sorting them with A/C No will definitely effect their
result.
Are records with the same 'Type', 'Status', and 'ZCurrency' values
always continguous in your set of records?

Yes, if records are having same "Type","Status" and "ZCurrency" , they
are always contiguous but their "A/C No" are not in sorted order.

so , my concern is to sort the contigous records having same
"Type","Status" and "ZCurrency" with their "A/C No"'s
It looks like you want to sort by: 1) 'Type', 2) 'Status', 3)
'ZCurrency', and 4) 'A/C No'. Is that correct? Try this (untested):
@sorted = sort { $a->{'Type'} cmp $b->{'Type'} ||
$a->{'Status'} cmp $b->{'Status'} ||
$a->{'ZCurrency'} cmp $b->{'ZCurrency'} ||
$a->{'A/C No'} cmp $b->{'A/C No'} } @records;

You can help us help you by writing a complete, short-as-possible,
working program that demonstrates the problem you are having. In your
case, I would recommend testing with fewer and shorter data records
until you get the sort part working. Something link:

@records = (
{ a => 1, b => 1, c => 1, d => 1 },
{ a => 1, b => 1, c => 1, d => 2 },
{ a => 1, b => 1, c => 1, d => 3 },

(you get the picture, I hope).

Good luck.

Thanks,
Raj
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top