Solved

Sorting an array?

Posted on 2000-02-26
39
227 Views
Last Modified: 2010-03-05
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.
0
Comment
Question by:treyjeff
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 14
  • 11
  • 7
  • +3
39 Comments
 
LVL 84

Expert Comment

by:ozo
ID: 2561654
perldoc -f sort
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2561716
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.
0
 
LVL 84

Expert Comment

by:ozo
ID: 2561741
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
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 8

Expert Comment

by:shlomoy
ID: 2562128
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?
0
 

Expert Comment

by:KishoreS78
ID: 2563891
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.
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2564809
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.
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2565708
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;}
0
 
LVL 5

Expert Comment

by:PC_User321
ID: 2566595
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{$_};
}
0
 
LVL 5

Expert Comment

by:PC_User321
ID: 2566670
If you want them sorted from highest to lowest, then replace the 'foreach' line with

foreach (sort {$b <=> $a} keys %Hash) {
0
 
LVL 84

Expert Comment

by:ozo
ID: 2566697
See also Sort::Fields
0
 
LVL 8

Expert Comment

by:shlomoy
ID: 2567887
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`





0
 
LVL 8

Expert Comment

by:shlomoy
ID: 2567915
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.
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2569186
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

0
 
LVL 1

Author Comment

by:treyjeff
ID: 2572637
Sorry guys, will try it sometime Thursday or Friday unless I can sneak some time here at work :)
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2584031
Just an update, will be testing tomorrow.
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2586048
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

0
 
LVL 5

Expert Comment

by:PC_User321
ID: 2586067
Your code looks good.
Glad I could help.
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2587198
Adjusted points to 50
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2587199
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.
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2588097
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!!
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2588138
maneshr, there is just so much code to it and I have no idea what half of it means.
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2588182
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.
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2588276
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
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2588419
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;}

0
 
LVL 16

Expert Comment

by:maneshr
ID: 2588773
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.
0
 
LVL 16

Accepted Solution

by:
maneshr earned 50 total points
ID: 2588870
here is the same code with more features. you can sort in ascending or descending order. Also you can only display certains columns from the sorted array.

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

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

##      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 ...
##      ... Sort order "a" = ascending, "d"= descending & ...
##      ... Array to sort
@new=&my_sort(1,"n","d",@recs);

##      Print out the array after the sorting has been done.
foreach(@new){
      @which_cols=split(/\|/,$_);
      ##      Only show columns 1, 3, 7, 23, 2 IN THAT ORDER
      foreach(1,3,7,23,2){
            print $which_cols[$_],"\t";
      }
      print "\n";
}

##      Subroutine that does the actual sort.
##      Accepts 4 params viz. the column number to sort
##      Column no starts with 1. The type of sort numeric or alphabetic
##      Finally the sort order is required. Default order is ascending
##      The array that needs to be sorted.
sub my_sort{
      ($col,$type,$sort_order,@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 &my_sort(3,"z",@array,"a"), we ignore the z and perform an alphabetic sort ("a").
      $type="a" if $type!~ /^n$/i;      ##      Default Alphabetic sort

      ##      To take care of conditions where user has passed anything other
      ##      ... than a "d" or "D". Eg. if the user has said &my_sort(3,"z",@array,"q"), we ignore the q and sort in ascending order("a").
      $sort_order="a" if $sort_order!~ /^d$/i;      ##      Default Ascending Sort order

      ##      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 @tmp));      ## 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
            if ($sort_order=~ /^d$/i){      ##      Descending sort requested
                  ##      Sort the array by number using the bynum subroutine
                  @new_arr=reverse sort bynum @new_arr
            }else{      ##      Default, Ascending sort order requested
                  @new_arr=sort bynum @new_arr
            }
      }else{      ##      Alphabetic sort
            if ($sort_order=~ /^d$/i){      ##      Descending sort requested
                  ##      Sort the array by alphabets using the byalp subroutine
                  @new_arr=reverse sort byalp @new_arr
            }else{      ##      Default, Ascending sort order requested
                  @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;}

0
 
LVL 1

Author Comment

by:treyjeff
ID: 2588991
Excellent way to srt.  Quite hard to know what was going on so I appreciate the extra effort you put in.
0
 
LVL 5

Expert Comment

by:PC_User321
ID: 2589127
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];
}
0
 
LVL 5

Expert Comment

by:PC_User321
ID: 2589131
With you data, you must change [3] to [23]
0
 
LVL 5

Expert Comment

by:PC_User321
ID: 2589275
With you data, you must change [3] to [23]
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2589440
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?

0
 
LVL 16

Expert Comment

by:maneshr
ID: 2589465

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.

0
 
LVL 5

Expert Comment

by:PC_User321
ID: 2589586
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]);
}

0
 
LVL 1

Author Comment

by:treyjeff
ID: 2589810
Manesh, I get a 500 server error with yours.
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2591459
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.
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2592657
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
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2592923
what solved the "500 server error"??
0
 
LVL 1

Author Comment

by:treyjeff
ID: 2593030
It was that I had the table tag inside the first for loop instead of outside it.
0
 
LVL 16

Expert Comment

by:maneshr
ID: 2593421
ahhh!!!
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Perl script to parse log and delete the file 17 183
hard perl script 16 168
Merge files & delete row based on criteria using Perl. 1 111
Replace  text in a file 2 135
I have been pestered over the years to produce and distribute regular data extracts, and often the request have explicitly requested the data be emailed as an Excel attachement; specifically Excel, as it appears: CSV files confuse (no Red or Green h…
In the distant past (last year) I hacked together a little toy that would allow a couple of Manager types to query, preview, and extract data from a number of MongoDB instances, to their tool of choice: Excel (http://dilbert.com/strips/comic/2007-08…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question