Solved

Sorting an array?

Posted on 2000-02-26
39
189 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
  • 14
  • 11
  • 7
  • +3
39 Comments
 
LVL 84

Expert Comment

by:ozo
Comment Utility
perldoc -f sort
0
 
LVL 1

Author Comment

by:treyjeff
Comment Utility
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
Comment Utility
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
 
LVL 8

Expert Comment

by:shlomoy
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
See also Sort::Fields
0
 
LVL 8

Expert Comment

by:shlomoy
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Just an update, will be testing tomorrow.
0
 
LVL 1

Author Comment

by:treyjeff
Comment Utility
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
Comment Utility
Your code looks good.
Glad I could help.
0
 
LVL 1

Author Comment

by:treyjeff
Comment Utility
Adjusted points to 50
0
 
LVL 1

Author Comment

by:treyjeff
Comment Utility
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
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 16

Expert Comment

by:maneshr
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
With you data, you must change [3] to [23]
0
 
LVL 5

Expert Comment

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

Author Comment

by:treyjeff
Comment Utility
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
Comment Utility

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
Comment Utility
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
Comment Utility
Manesh, I get a 500 server error with yours.
0
 
LVL 16

Expert Comment

by:maneshr
Comment Utility
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
Comment Utility
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
Comment Utility
what solved the "500 server error"??
0
 
LVL 1

Author Comment

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

Expert Comment

by:maneshr
Comment Utility
ahhh!!!
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

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…
Checking the Alert Log in AWS RDS Oracle can be a pain through their user interface.  I made a script to download the Alert Log, look for errors, and email me the trace files.  In this article I'll describe what I did and share my script.
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…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

728 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now