[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [MacPerl] sorting arrays



On Wed, Jun 16, 1999 at 09:21:16AM -0400, cetasix@pop.erols.com wrote:
> I am trying to sort a simple text file:
> 
> Janssen||Willem
> Hinders||Trintje
> Beving||John
> Beving||Henrietta
> Beving||Ubbe
> Beving||Henry
> Beving||Henry
> Beving||Etta
> Beving||Minnie
> Beving||Bertha
> Willemssen||male
> Willemssen||male
> Willemssen||Wopka(e)
> Brower||Coba
> Brower||John
> Brower||Bertha
> 
> I'm using the following code and it does not seem to sort them.

Are you trying to sort the whole file by line, or each individual line by
field?  The code below sorts each line by field (but not very well, I'm
afraid).

> if(open(INFILE,"names.txt") || die("Cannot open names.txt")) {

There is no reason for that expression to be the conditional for an if
statement.  It should simply be used by itself:

open(INFILE,"names.txt") || die("Cannot open names.txt: $!\n");

Note that you should include $! so you know _why_ it could not open
names.txt.

> 	while (<INFILE>) {
> 		@fields = $_;

If you assign a scalar to an array, that array is guaranteed to contain
exactly one element.  Thus, there is no need to use a loop to process the
contents of the array:

> 		foreach $field (@fields) {

This loop iterates over a single-element array.  Very silly.

> 			@array = split /\|\|/, $field;
> 			@array = sort(@array);

Now you've sorted the line by fields.

> 			chomp($array[0],$array[1]);

Since this array only has two elements anyway, this line is just the long
way of writing:

chomp(@array)

But this is the wrong place to do it, anyway.  You should chomp the line
when you read it in, not after you've processed it and rearranged the
elements.

> 			$lastname = $array[0];
> 			$firstname = $array[1];

Since you just sorted @array alphabetically, $array[0] may not be the last
name anymore; if the person's name is John Smith, then $array[0] will
contain the first name.

> 			print "$lastname, $firstname\n";
> 		}
> 	}
> 	close(INFILE);
> }
> 
> It does not seem to work. Is there something I'm missing in the code?
> 

If you want to sort the entire file by line, you have to read the entire
file into memory.  You can then use a Schwartzian Transform to efficiently
sort the lines:

#!/usr/local/bin/perl
# untested

open(INFILE,"names.txt") || die("Cannot open names.txt: $!\n");

@lines = <INFILE>;  # read entire file into @lines

chomp(@lines);      # remove newlines

@lines = map { $_->[0] }
         sort { $a->[1] cmp $b->[1] || $a->[2] cmp $a->[2] }
         map { [$_, (split /\|\|/) ] }
         @lines;    # sort by lastname, then firstname

foreach (@lines) {  # convert '||' to ', ' and print
    s/\|\|/, /;
    print "$_\n";
}


HTH!

Ronald

===== Want to unsubscribe from this list?
===== Send mail with body "unsubscribe" to macperl-request@macperl.org