Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Sorting Problem ... 2

Status
Not open for further replies.

calabama

Programmer
Feb 19, 2001
180
0
0
US
Hello all

I have this little for each loop that sorts data field $rec->[3] numerically first then alphabetically. The $rec->[3] data fields only contain the numbers (1,2,3,4).

I would like all the sorted data where

$rec->[3] data fields contain the number (1) to be put into a seperate array.

all the sorted data where $rec->[3] data fields contain the number (2) to be put into a seperate array.

all the sorted data where $rec->[3] data fields contain the number (3) to be put into a seperate array.

all the sorted data where $rec->[3] data fields contain the number (4) to be put into a seperate array.

Thanks for any help

Tim
Code:
foreach my $rec (
sort{
$a->[3] <=> $b->[3]||$a->[2] cmp $b->[2]}@records 
)
{
$rowstr .=  $rec->[1] .'. '. $rec->[2].'.'.$rec->[3].'.'.$rec->[4].'<BR>'}
    
print &quot;$rowstr\n&quot;;

}

In the begining
Let us first assume that there was nothing to begin with.
 
Here's one possibility.
Code:
# Build an array for symbolic reference
for (1..4) {
  push (@symb_array_refs, 'array' . $_);
}

...

foreach my $rec (
sort{ $a->[3] <=> $b->[3]||$a->[2] cmp $b->[2] }@records
)
{
  # Use index 3 in $rec as the index into symbolic names
  # array. Push record onto array pointed to via symbolic
  # reference
  push @{ $symb_array_refs[ $rec->[3] ] }, $rec;
}

...
After the sort you would have 4 arrays (@array1, @array2, @array3, @array4) to do what you want. If index 3 changes to include more values then just update the initial for loop that builds the array names.

Hope that helps.
 
I always thought the use of symbolic references was not good in perl.

In the begining
Let us first assume that there was nothing to begin with.
 
seeing as usige's version breaks under -w and use strict....

try this:

#!/usr/bin/perl -w
use strict;

my %values;
foreach (sort map { &quot;$_->[3]#$_->[2]&quot; } @records) {
$_ =~ /(\d)#(.*)$/;
push @{$values{$1}}, $2;
}

By combining the fields you want, the sort can do a lexical sort, thus saving computation time. Each sorted array is then in each hash element of $value{1}, $value{2} , etc.

Your original question and code were a little at odds. I assume you meant field 4 ($rec->[3]) to be sorted numerically and contain a single digit (1-4), and field 2 ($rec->[2]) was to be sorted alphabetically.

Barbie
Leader of Birmingham Perl Mongers
 
Thanks so much

It seems to work much better but I am still getting an error when trying to print. I guess there is something wrong with LINE 43. I marked it below in the code.

################# ERROR ##############

Can't use string (&quot;1#Escobar&quot;) as an ARRAY ref while &quot;strict refs&quot; in use at /u/web/smpsvc/cgi-local/schedules/cleaners/readfile_temp.cgi line 43.


################## CODE ################


Code:
my %values;
foreach (sort map { &quot;$_->[3]#$_->[2]&quot; } @records) {
    $_ =~ /(\d)#(.*)$/;
    push @{$values{$1}}, $2;

*** START LINE 43 ***   
$rowstr .=  $_->[1] .'. '. $_->[2].'<BR>'}
***** END LINE 43 ***

print &quot;$rowstr\n&quot;;

}

In the begining
Let us first assume that there was nothing to begin with.
 
The
Code:
map
after your sort means that $_ no longer holds a record, it now holds a string. You would need to dereference on line 43 like:
Code:
$rowstr .=  $values{$1}->[1] . '. ' . $values{$1}->[2].'<BR>';
I assume that @records is an array of arrays (?).

The push is only pushing the third element of each record onto the array hashes. The new hash will not have all the record data.

This might be less optimized but I think it will do what I assume you want without symbolics:
Code:
my ($rec, $reckey, $rowstr, %indexed_rec);
foreach $rec (@records) {
  push @{$indexed_rec{$rec->[3]}}, $rec;
}

foreach $reckey (sort keys %indexed_rec) {
  foreach $rec (sort { $a->[2] cmp $b->[2] } @{$indexed_rec{$reckey}} ){
    $rowstr .=  $rec->[1] .'. '. $rec->[2].'.'.$rec->[3].'.'.$rec->[4].'<BR>'
  }
  print &quot;$rowstr\n&quot;;
}
 
calabama, I had taken your question at face value, in that you only wanted to store the appropriate fields in the array. If you want to still have a reference to the original record....

#!/usr/bin/perl -w
use strict;

my %values;
foreach (sort {$a->[0] cmp $b->[0]} map { [&quot;$_->[3]#$_->[2]&quot;,$_] } @records) {
my $rec = $_->[1];
push @{$values{$rec->[3]}}, $rec->[2];
}


$rec will now reference the original record.

Barbie
Leader of Birmingham Perl Mongers
 
Thanks, barbie. I spent the better part of a half hour trying to work the full record into your map solution. It never even crossed my mind to have map return an array.

I'd give you two stars if I could. Need to tuck this one away in my goodie bag.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top