Link to home
Start Free TrialLog in
Avatar of treyjeff
treyjeff

asked on

Sorting an array?

I'd like to do the following:

I have guys make over/under picks and it saves the selections to a file.  I want to have the selections checked against another "result file" if you will.  Then for each guys I want it to generate standings.  How would one propose I do that and have them listed from top to bottom.  I can award say 5 points for each right answer and even keep the score in the owner file.  I want to keep it basic as well so that I, a bieginner can understand it.
Avatar of ozo
ozo
Flag of United States of America image

perldoc -f sort
Avatar of treyjeff
treyjeff

ASKER

Ozo, why do you keep posting that stuff?  Besides, where would I enter that?  I don't have access to a prompt to test this stuff out on.
What do you have access to?  How were you expecting to develop your program?
But if you don't have access to perl or perldoc, you can still find documentation here:
http://www.perl.com/pub/doc/manual/html/pod/perlfunc/sort.html
Assumming your array is @my_array
you can have it sorted by:

@my_sorted_array = sort @my_array;

is that what you had in mind?
can u be more clear in what exactly u want .u say u want to sort an array ?
but what does ur array have in it?
if u just wanna sort then
Sshlomoy has given u the answer.
I have access to FTP to upload my scripts, that's it.  I write my scripts in notepad and if I run into trouble I debug with Visual Perl Edit.  If I have an array that breaks out to the following:

team, owner, ownersemail, score, icqnumber

I want to sort the array on the score element.  It's actually a file I read into an array so it may look like this:

Toronto|Jeff|jeff@hyrum.net|98|571803
Baltimore|Ozo|email@email.com|12|123456
Detroit|Schlomoy|email@email.com|78|34567
Calgary|Kishore|email@email.com|67|98765

I want it sorted by the score element so I can print it out into an html file.
here is a very flexible sorting routine.

you can customize it to sort ANY column that you want either numerically of alphabetically.

by adding some more code you can reverse sort too!!

===score
Toronto|Jeff|jeff@hyrum.net|98|571803
Baltimore|Ozo|email@email.com|12|123456
Detroit|Schlomoy|email@email.com|78|34567
Calgary|Kishore|email@email.com|67|98765


========score.pl
#!/usr/local/bin/perl

$WebFileName = "/home/webuser/manesh/tmp/score";

open(MYFILE,"$WebFileName") || die $!;
@recs=<MYFILE>;
close(MYFILE);

##  Column num (starting from 1), type of sort
##  n = numeric, a = alphabetic & Array to sort
@new=&my_sort(4,"n",@recs);

## Here are some more samples that you could try
##@new=&my_sort(1,"a",@recs);
##@new=&my_sort(2,"a",@recs);

##  Print out the results
foreach(@new){
  print $_;
}

sub my_sort{
  ($col,$type,@arr)=@_;

  $col--;
  $type="a" if $type!~ /^n$/i;  ##  Default Alphabetic sort

  foreach(@arr){
    @tmp=split(/\|/,$_);
    return 0 if ($col<0 || $col>(scalar @arr)); ## Invalid col no.
    $new_arr=join('|',$tmp[$col],$_);
   push(@new_arr,$new_arr);
  }

  if ($type=~ /^n$/i){    ##  Numeric Sort
    @new_arr=sort bynum @new_arr
  }else{
    @new_arr=sort byalp @new_arr
  }

  @arr="";  ##  Re initialize the array
  foreach(@new_arr){
    @tmp=split(/\|/,$_);
    shift(@tmp);  ##  Remove the 1st column
    $new_arr=join('|',@tmp);
    push(@arr,$new_arr);
  }

  return @arr;
}

sub bynum{ $a <=> $b;}

sub byalp{ $a cmp $b;}
open (F, "input.txt");
while (<F>) {
   $Line = $_;
   @Field = split /\|/, $Line;
   # Build a hash, using the score as the
   # key and the whole line as the value
   $Hash{$Field[3]} = $Line;
}
# Print the contents of the hash in score order
foreach (sort keys %Hash) {
   print $Hash{$_};
}
If you want them sorted from highest to lowest, then replace the 'foreach' line with

foreach (sort {$b <=> $a} keys %Hash) {
See also Sort::Fields
what's wrond using UNIX's sort?


cat my_file | sort -k column

example:

Consider the file sortMe:
bbb     aaa     zzz      eee
ccc     ddd     eee     fff
aaa     fff     ggg     xxx
ddd     vvv     fff     ggg
aaa     bbb     www     ddd


$> cat sortMe | sort -k 1
aaa     bbb     www     ddd
aaa     fff     ggg     xxx
bbb     aaa     zzz      eee
ccc     ddd     eee     fff
ddd     vvv     fff     ggg

$> cat sortMe | sort -k 2
bbb     aaa     zzz      eee
aaa     bbb     www     ddd
ccc     ddd     eee     fff
aaa     fff     ggg     xxx
ddd     vvv     fff     ggg


from PERL you can call this using the command substitution:

`cat sortMe | sort -k 3 > soreted`





Solving it in Perl:

read in the file lines into a hash, where the key is the data in the column you want to sort by and the data is all the line.

After reading in the file, sort your hash using sort keys.
Hi  treyjeff ,

did you get a chance to evaluate the various solutions proposed by the experts??

which one worked for you?? do let us know....

Thanks

Sorry guys, will try it sometime Thursday or Friday unless I can sneak some time here at work :)
Just an update, will be testing tomorrow.
PC USer I have tried yours as it appears the least amount of code.  My code for what I'm doing is already huge.  Here is the code I have to see the standings, all it does is display the last record:

#!/usr/bin/perl  
require "cgi-lib.pl";

#set content type  
print &PrintHeader;

#initialize variables
$optionfile = "/usr/local/www/htdocs/hyrum/polldata/firstgame.txt";

open (FILE, "$optionfile");
while (<FILE>) {
   $Line = $_;
   @Field = split /\|/, $Line;
   # Build a hash, using the score as the
   # key and the whole line as the value
   $Hash{$Field[23]} = $Line;
}
# Print the contents of the hash in score order
foreach (sort {$b <=> $a} keys %Hash) {
   print $Hash{$_};
   print <BR>
}

###End of program

Your code looks good.
Glad I could help.
Adjusted points to 50
I'm not ready to accept as it doesn't yet do what I was looking for.  I want all the records to display :)  For some reason it only prints one record and it happens to be the last one in the file.  While it prints every field and that is ok, if I could only print a few fields like 5,6,23 that would be even better.
treyjeff,

your should probably try the code i had provided earlier. Like i said, its a very flexible sorting routine.  You can customize it to sort ANY column that you want either numerically of alphabetically.
By adding some more code you can reverse sort too!!
maneshr, there is just so much code to it and I have no idea what half of it means.
yes, you are right. due to this somewhat large code you have the flexibility of sorting on any column. Also i have put in validation checks so that you can just take the code as-is and integrate it with your code, without having to do any more checking.

However the heart of the code is this snippet, that takes the array that you passed and sorts it.

foreach(@arr){
  @tmp=split(/\|/,$_);
  return 0 if ($col<0 || $col>(scalar @arr)); ## Invalid col no.
  $new_arr=join('|',$tmp[$col],$_);
  push(@new_arr,$new_arr);
}


if you want me to comment every line of the code and also explain the logic, pl let me know.
Sure if you don't mind doing that, that would be good.  You can even email me with all the comments if that's easier. jeff@hyrum.net
here is the commented code. i have put in examples whereever possible. in case you need more commenting/examples, pl let me know

==================score.pl
#!/usr/local/bin/perl

##      Full Path to the File that needs to be sorted
$WebFileName = "/home/webuser/manesh/tmp/score";

##      Open the file for reading. If open is unsuccessfull...
##      ... show the reason and exit the program
open(MYFILE,"$WebFileName") || die $!;
##      "Slurp" the ENTIRE file, so that every line in the ...
##      ... file is stored as an element in the array
@recs=<MYFILE>;
close(MYFILE);      ##      Close the file

##      Column num (starting from 1), type of sort
##      n = numeric, a = alphabetic &      Array to sort
@new=&my_sort(2,"a",@recs);

##      Print out the array after the sorting has been done.
foreach(@new){
      print $_;
}

##      Subroutine that does the actual sort.
##      Accepts 3 params viz. the column number to sort
##      Column no starts with 1. The type of sort numeric or alphabetic
##      The array that needs to be sorted.
sub my_sort{
      ($col,$type,@arr)=@_;

      ##      Deduct 1 from the column.
      ##      We do this because in PERL array subscript starts with 0.
      ##      So in human terms when we say column 2 it means column 1 in PERL terms!!
      $col--;

      ##      To take care of conditions where user has passed anything other
      ##      ... than a "n" or "N". Eg. if the user has said &mt_sort(3,"z",@array), we ignore the z and perform an alphabetic sort ("a").
      $type="a" if $type!~ /^n$/i;      ##      Default Alphabetic sort

      ##      Process every element of the array
      foreach(@arr){
            ##      Split every line using | as the delimiter.
            @tmp=split(/\|/,$_);
            ##      After we split we know how many columns are ..
            ##      ... present in every record. Now we have to ...
            ##      ... take care of situations where the user might want ..
            ##      ... to sort on non-existant or invalid columns.
            ##      Eg. Each record has 6 columns and the user has passed 7 or 8
            ##      ... or -1 etc...
            return 0 if ($col<0 || $col>(scalar @arr));      ## Invalid col no.

            ##      This is important. We take the column that the user wants ...
            ##      ... to sort on and pre-pend it to the record itself.

            ##      Let's say the record is ...
            # Toronto|Jeff|jeff@hyrum.net|98|571803
            ##      ...& the user wants to sort on the 2nd column (PERL subscript 1).
            $new_arr=join('|',$tmp[$col],$_);
            ##      After the above the record will be...
            # Jeff|Toronto|Jeff|jeff@hyrum.net|98|571803

            ##      Store this new record in an array
            push(@new_arr,$new_arr);
      }

      ##      Determine the type of sort
      if ($type=~ /^n$/i){            ##      Numeric Sort
            ##      Sort the array by number using the bynum subroutine
            @new_arr=sort bynum @new_arr
      }else{      ##      Alphabetic sort
            ##      Sort the array by alphabets using the byalp subroutine
            @new_arr=sort byalp @new_arr
      }

      @arr="";      ##      Re initialize the array
      ##      Remember our sort is done, but we still have that...
      ##      ...extra column at the beggining that we must remove!!
      foreach(@new_arr){
            ##      Split every line using | as the delimiter.
            @tmp=split(/\|/,$_);
            shift(@tmp);      ##      Remove that 1st column
            ##      So before the shift if we had....
            # Jeff|Toronto|Jeff|jeff@hyrum.net|98|571803
            ##      After th shift we will have...
            # Toronto|Jeff|jeff@hyrum.net|98|571803

            ##      Join the array as one record...
            $new_arr=join('|',@tmp);
            ##      ...& store it in another array.
            push(@arr,$new_arr);
      }

      ##      Return the final array (in sorted order)
      return @arr;
}

sub bynum{ $a <=> $b;}

sub byalp{ $a cmp $b;}

There is a typo in the code above.

Please change ....

  return 0 if ($col<0 || $col>(scalar @arr); ## Invalid col no.

to ..............


  return 0 if ($col<0 || $col>(scalar @tmp)); ## Invalid col no.
ASKER CERTIFIED SOLUTION
Avatar of maneshr
maneshr

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Excellent way to srt.  Quite hard to know what was going on so I appreciate the extra effort you put in.
Wow, things have developed since I left my computer!

The trouble with my sort was that it did not allow for duplicates.
Here is the corected code:

open (FILE, "$optionfile") or die $!;
@Sorted = sort byScore <FILE>;
print @Sorted;

sub byScore {
   @FieldA = split /\|/, $a;
   @FieldB = split /\|/, $b;
   $FieldB[3] <=> $FieldA[3];
}
With you data, you must change [3] to [23]
With you data, you must change [3] to [23]
PC User, I will check it out as well and perhaps give you some points as well in another question, especially if you can get it to show how to print like I'm aking below.

Manesh, how can I change

foreach(2,24){
print $which_cols[$_],"\t";
}
print "\n";
}
So that I can add some HTML around it?  For example a table and print one (2) in one column and (24) in the one next to it?


print "Content-type: text/html\n\n";

print "<TABLE BORDER=1>\n";

foreach(@arr){
  foreach(2,24){
    print "<TD>",$which_cols[$_],"</TD>";
  }
  print "<TR>\n";
}

print "</TABLE>\n";


This will print your results in an HTML table.

In my code the contents of the table is printed like this:

foreach $Line (@Sorted) {
   @Fields = split /\|/, $Line;
   printf("<TD>%s<\/TD><TD>%s<\/TD><TR>\n",  $Fields[2], $Fields[24]);
}

Manesh, I get a 500 server error with yours.
check the permission of the .pl file and see if you can execute the same from the command prompt.

i tried the above and it works fine on my system.
Sorry, was late.  I actualy did get it to run lastnight.  Can be seen at www.hyrum.net/cgi-bin/cgiwrap/hyrum/standings.pl

I'm just going to see how to add some nice formatting around it and everything :)  Also, still going to try PCUsers
what solved the "500 server error"??
It was that I had the table tag inside the first for loop instead of outside it.
ahhh!!!