Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sorting based on string value

0 views
Skip to first unread message

Ninja67

unread,
Dec 4, 2006, 5:46:30 PM12/4/06
to
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!

Paul Lalli

unread,
Dec 4, 2006, 6:14:30 PM12/4/06
to

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

Gunnar Hjalmarsson

unread,
Dec 4, 2006, 8:49:21 PM12/4/06
to
Ninja67 wrote:
> 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;

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl

Mumia W. (reading news)

unread,
Dec 4, 2006, 8:51:17 PM12/4/06
to

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);

--
paduille.4...@earthlink.net

Mumia W. (reading news)

unread,
Dec 4, 2006, 11:31:59 PM12/4/06
to

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.


--
paduille.4...@earthlink.net

Uri Guttman

unread,
Dec 5, 2006, 12:39:36 AM12/5/06
to
>>>>> "MW(n" == Mumia W (reading news) <paduille.4...@earthlink.net> writes:

>> 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;
>> }

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

--
Uri Guttman ------ u...@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org

Gunnar Hjalmarsson

unread,
Dec 5, 2006, 1:15:20 AM12/5/06
to
Uri Guttman wrote:

>>>>>>"MW(n" == Mumia W (reading news) writes:
>
> >> 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;
> >> }
>
> 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. :)

Ninja67

unread,
Dec 5, 2006, 12:41:46 PM12/5/06
to

You rock! That's awesome.

0 new messages