Sorting based on string value

N

Ninja67

I've got the following code in a script:

my $cost_order = "A2yB";
my @series_cost = ();

for (@{$struct->{tree}->[0]->{rectangle}}) {
my $rec_string = "<table><tr><td ";
$rec_string .= ' meascode="'.$_->{meascode}.'"></td></tr></table>';

SWITCH: {
if ($_->{datafile} =~ /^cost/) { push(@series_cost, $rec_string);
last SWITCH; }
$nothing = 1;
}
}

Now that I have my array filled, I want to sort the contents of each
array by the "meascode" attribute. Each meascode attribute is a single
character that matches one of the characters in the $cost_order string.
How can I sort an array based on the order of the characters in the
$cost_order string?

So my array might contain:
<table><tr><td meascode="y"></td></tr></table>
<table><tr><td meascode="2"></td></tr></table>
<table><tr><td meascode="A"></td></tr></table>
<table><tr><td meascode="B"></td></tr></table>

but I need it to contain:
<table><tr><td meascode="A"></td></tr></table>
<table><tr><td meascode="2"></td></tr></table>
<table><tr><td meascode="y"></td></tr></table>
<table><tr><td meascode="B"></td></tr></table>

Thanks!
 
P

Paul Lalli

Ninja67 said:
I've got the following code in a script:

my $cost_order = "A2yB";
my @series_cost = ();

for (@{$struct->{tree}->[0]->{rectangle}}) {
my $rec_string = "<table><tr><td ";
$rec_string .= ' meascode="'.$_->{meascode}.'"></td></tr></table>';

SWITCH: {
if ($_->{datafile} =~ /^cost/) { push(@series_cost, $rec_string);
last SWITCH; }
$nothing = 1;
}
}

Now that I have my array filled, I want to sort the contents of each
array by the "meascode" attribute. Each meascode attribute is a single
character that matches one of the characters in the $cost_order string.
How can I sort an array based on the order of the characters in the
$cost_order string?

So my array might contain:
<table><tr><td meascode="y"></td></tr></table>
<table><tr><td meascode="2"></td></tr></table>
<table><tr><td meascode="A"></td></tr></table>
<table><tr><td meascode="B"></td></tr></table>

but I need it to contain:
<table><tr><td meascode="A"></td></tr></table>
<table><tr><td meascode="2"></td></tr></table>
<table><tr><td meascode="y"></td></tr></table>
<table><tr><td meascode="B"></td></tr></table>

Maybe I'm not understanding your goal, but why aren't you just sorting
the values in your original array, before looping through them and
putting them inside strings in a new array? Why would you want to fill
the array, convoluting your value, then have to loop back through that
string, parse out the data you just put in, so that you can compare it?

Change:
for (@{$struct->{tree}->[0]->{rectangle}}) {
To:
for (sort { $a->{meascode} cmp $b->{meascode} }
@{$struct->{tree}->[0]->{rectangle}}) {

Paul Lalli
 
G

Gunnar Hjalmarsson

Ninja67 said:
Now that I have my array filled, I want to sort the contents of each
array by the "meascode" attribute. Each meascode attribute is a single
character that matches one of the characters in the $cost_order string.
How can I sort an array based on the order of the characters in the
$cost_order string?

One way:

my @series_cost = (
'<table><tr><td meascode="y"></td></tr></table>',
'<table><tr><td meascode="2"></td></tr></table>',
'<table><tr><td meascode="A"></td></tr></table>',
'<table><tr><td meascode="B"></td></tr></table>'
);

my $cost_order = 'A2yB';

my @sorted;
while ( my $mc = chop $cost_order ) {
unshift @sorted, grep /code="$mc"/, @series_cost;
}

print map "$_\n", @sorted;
 
M

Mumia W. (reading news)

I've got the following code in a script:

my $cost_order = "A2yB";
my @series_cost = ();

for (@{$struct->{tree}->[0]->{rectangle}}) {
my $rec_string = "<table><tr><td ";
$rec_string .= ' meascode="'.$_->{meascode}.'"></td></tr></table>';

SWITCH: {
if ($_->{datafile} =~ /^cost/) { push(@series_cost, $rec_string);
last SWITCH; }
$nothing = 1;
}
}

Now that I have my array filled, I want to sort the contents of each
array by the "meascode" attribute. Each meascode attribute is a single
character that matches one of the characters in the $cost_order string.
How can I sort an array based on the order of the characters in the
$cost_order string?

So my array might contain:
<table><tr><td meascode="y"></td></tr></table>
<table><tr><td meascode="2"></td></tr></table>
<table><tr><td meascode="A"></td></tr></table>
<table><tr><td meascode="B"></td></tr></table>

but I need it to contain:
<table><tr><td meascode="A"></td></tr></table>
<table><tr><td meascode="2"></td></tr></table>
<table><tr><td meascode="y"></td></tr></table>
<table><tr><td meascode="B"></td></tr></table>

Thanks!

Use a hash table to store the values of y2AB and use that hash table to
help the sort comparison routine:

use strict;
use warnings;
use Data::Dumper;

my $count = 0;
my %cost_order = map +($_, $count++), qw(A 2 y B);
my @ms = map { meascode => $_ }, qw(y B 2 A);
my @series_cost = ();

for (@ms) {
my $rec_string = "<table><tr><td meascode='$_->{meascode}'>"
. " </td></tr></table>\n";
push @series_cost, $rec_string;
}

my @sorted = sort {
my @vals = "$a $b" =~ /meascode='([^']+)'/g;
$cost_order{$vals[0]} cmp $cost_order{$vals[1]};
} @series_cost;
print Dumper(\@sorted);
 
M

Mumia W. (reading news)

One way:

my @series_cost = (
'<table><tr><td meascode="y"></td></tr></table>',
'<table><tr><td meascode="2"></td></tr></table>',
'<table><tr><td meascode="A"></td></tr></table>',
'<table><tr><td meascode="B"></td></tr></table>'
);

my $cost_order = 'A2yB';

my @sorted;
while ( my $mc = chop $cost_order ) {
unshift @sorted, grep /code="$mc"/, @series_cost;
}

print map "$_\n", @sorted;

That's pretty cool. I almost wish I hadn't posted my own solution :)

It took me a couple of minutes to figure it out because the 'sort'
function appears nowhere in the code. It's an insertion sort, and it
uses the $cost_order without creating an external hash or anything, and
it takes three lines--pretty good.
 
U

Uri Guttman

MW(n> That's pretty cool. I almost wish I hadn't posted my own solution :)

MW(n> It took me a couple of minutes to figure it out because the 'sort'
MW(n> function appears nowhere in the code. It's an insertion sort, and it
MW(n> uses the $cost_order without creating an external hash or anything,
MW(n> and it takes three lines--pretty good.

and an insertion (or bubble) sort runs in O( N ** 2 ) which is very slow
for larger input lists.

given the above you can do this (tested):

use Sort::Maker ;

my @unsorted = (

'<table><tr><td meascode="y"></td></tr></table>',
'<table><tr><td meascode="2"></td></tr></table>',
'<table><tr><td meascode="A"></td></tr></table>',
'<table><tr><td meascode="B"></td></tr></table>',
) ;


my $sorter = make_sorter( 'GRT', string => qr/"(\w+)"/ ) ;
$sorter or die $@ ;

print map "$_\n", $sorter->( @unsorted ) ;


i agree that it would be better to sort the strings before adding the
html cruft but you can easily extract the key out of those strings with
a simple regex.

uri
 
G

Gunnar Hjalmarsson

Uri said:
MW(n> That's pretty cool. I almost wish I hadn't posted my own solution :)

MW(n> It took me a couple of minutes to figure it out because the 'sort'
MW(n> function appears nowhere in the code. It's an insertion sort, and it
MW(n> uses the $cost_order without creating an external hash or anything,
MW(n> and it takes three lines--pretty good.

and an insertion (or bubble) sort runs in O( N ** 2 ) which is very slow
for larger input lists.

Yep, it's not recommended for larger lists.
given the above you can do this (tested):

use Sort::Maker ;

my @unsorted = (

'<table><tr><td meascode="y"></td></tr></table>',
'<table><tr><td meascode="2"></td></tr></table>',
'<table><tr><td meascode="A"></td></tr></table>',
'<table><tr><td meascode="B"></td></tr></table>',
) ;


my $sorter = make_sorter( 'GRT', string => qr/"(\w+)"/ ) ;
$sorter or die $@ ;

print map "$_\n", $sorter->( @unsorted ) ;

That's an efficient solution, but not to the OP's problem. :)
 
N

Ninja67

Gunnar said:
One way:

my @series_cost = (
'<table><tr><td meascode="y"></td></tr></table>',
'<table><tr><td meascode="2"></td></tr></table>',
'<table><tr><td meascode="A"></td></tr></table>',
'<table><tr><td meascode="B"></td></tr></table>'
);

my $cost_order = 'A2yB';

my @sorted;
while ( my $mc = chop $cost_order ) {
unshift @sorted, grep /code="$mc"/, @series_cost;
}

print map "$_\n", @sorted;

You rock! That's awesome.
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top