Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

Array Sorting

by sreenath (Novice)
on Dec 14, 2010 at 11:20 UTC ( #877047=perlquestion: print w/replies, xml ) Need Help??
sreenath has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am reading from a .csv file which is as follows:
names,age Rahul,25 Manu,36 Vijay,41 Tushar,23 Hetal,54 Binoy,19 Vikram,16
My program is like this:
$file='a.csv'; open (a,$file) || die ("couldnt open file"); while ($line=<a>) { @array=split(/,/,$line); @array1=split(/\n/,$array[1]); @array2=sort {$a <=> $b}(@array1); print "@array2"; }
But the array is not sorting according to the age.Can ypu help? Many thanls for your replies.

20101215 Janitored by Corion: Added formatting, code tags, as per Writeup Formatting Tips

Replies are listed 'Best First'.
Re: Array Sorting
by ELISHEVA (Prior) on Dec 14, 2010 at 12:03 UTC

    Please, when you post code, surround it with <code> ... my code here ... </code> tags. Otherwise all the formatting gets lost and we can't read with any ease what you wrote.

    That being said, it appears that you are confounding two very different meanings for the word "array". In one part of your code, you are viewing the line you read in as an array of comma delimited fields, i.e.  @array=split(/,/ $line). In another part of your code, when you sort, you are viewing the collection of records (one per line) as an array. Perl is confused because the "array" you are sorting to put the records in age order is the array of fields. All you are doing in your sort is sorting the field values within a single record, not the records.

    Human beings can handle such ambiguities well, but computer programs are much less tolerant. You can have two meanings of arrays, BUT you must use two different structures for each meaning:

    • array of fields (one per line): A simple array of strings, one for each field.
    • array of records: an array of array references (AoA), where each element of the array is an array reference storing a different line that you have read in.

    Thus, your code should look something like this.

    my @aRecords; my $iRecord=0; while ($line = <INPUT_FILE>) { my @aFields = split(/,/, $line); $aRecords[$iRecord] = \@aFields; # \@ creates an array reference $iRecord++; } # now that you have read in all the lines, you can sort them # assuming age is the second field, it will be stored at # index 1 (fields are numbered starting at 0) my @aSortedRecords = sort { $a->[1] <=> $b->[1] } @aRecords;

    You'll need to use an array reference to accomplish this, please take a look at perllol, and possibly perlref and perldsc as well.

    Update: expanded explanation of why code doesn't work and clarified description of AoA.

Re: Array Sorting
by jethro (Monsignor) on Dec 14, 2010 at 12:01 UTC

    Please use <code> tags so that your script looks like a real script and '$array1' looks like '$array[1]'

    Also you need to debug your program. That is relatively easy, just add a few print statements that tell you what array1 or array2 looks like

    You often will see immediately where your program doesn't do what you want. For example you seem to first split for commas (quite sensible) and then afterwards for line endings (\n) which really doesn't make sense since you only read your file one line at a time.

Re: Array Sorting
by Utilitarian (Vicar) on Dec 14, 2010 at 12:06 UTC
    First a word of advice on your formatting, you should surround code and formatted data with <code> tags as otherwise it becomes difficult to read. You had to go through a preview page and must have seen this yourself, it should look more like this:
    names,age Rahul,25 Manu,36 Vijay,41 Tushar,23 Hetal,54 Binoy,19 Vikram,16
    $file='a.csv'; open (a,$file) || die ("couldnt open file"); while ($line=<a>){ @array=split(/,/,$line); @array1=split(/\n/,$array[1]); @array2=sort {$a <=> $b}(@array1); print "@array2"; }
    This is just wrong, you should use the existing Text::CSV module, however if this is home work you should do something like the following (assumes that names are unique)
    • Read each line of the file into a hash of name=>agesplitting on ,
    • Sort the hash by value using the Schwartzian transform(understanding how this works will enlighten you greatly)

    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: Array Sorting
by Corion (Pope) on Dec 14, 2010 at 11:30 UTC

    You are talking about "the array", but you have at least three variables, named @array, @array1 and @array2. Which one do you mean?

    Also, are you sure that what you are programming makes sense? It seems to me that your variables do not contain what you think they do. You are sorting and printing within your loop. This is most unlikely what you want if you want to sort the complete file.

Re: Array Sorting
by prasadbabu (Prior) on Dec 14, 2010 at 12:08 UTC

    Hi Sreenath,

    Here is one way to read csv file and process your data. Here no need to split your data for sorting as you have done in your coding.

    use strict; use Text::CSV::Simple; my $parser = Text::CSV::Simple->new; my @data = $parser->read_file("d:\\prasad\\projects\\tools\\test.csv") +; print "Name - Age\n"; print "__________\n"; print $_->[0],' - ', $_->[1],"\n" for (sort {$a->[1] <=> $b->[1]} @d +ata); output: ======= Name - Age __________ Vikram - 16 Binoy - 19 Tushar - 23 Rahul - 25 Manu - 36 Vijay - 41 Hetal - 54


      HI Prasad,thanks for your reply. Is there no way I can sort ,if i split????

        Yes, as ELISHEVA suggested, you can do with AOA. His solution will work as per your requirement based on splitting.


Re: Array Sorting
by sundialsvc4 (Abbot) on Dec 14, 2010 at 14:53 UTC

    You probably need to take a slightly-different approach in building your data structure:  

    1. Initialize an empty array.
    2. Use a regular expression to compress all occurrences of multiple blanks into a single blank.
    3. split the string on blanks into a temporary array.
    4. Loop through this array, and split each element in turn, based on commas.   For each element, push a hashref onto the array in step #1.
    5. Now, you can sort that array (from #1), using a function that considers the hash-elements.   The difference here is that there is only one array being sorted, and each element within that array is a hashref containing two keys.

Re: Array Sorting
by Tux (Abbot) on Dec 15, 2010 at 17:07 UTC

    Putting all the advices together, with a few changes gives me:

    use strict; use warnings; use autodie; use Text::CSV_XS; my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 }); open my $fh, "<:encoding(utf-8)", "a.csv"; my @hdr = @{$csv->getline ($fh)}; my @arr; while (my $row = $csv->getline ($fh)) { push @arr, $row; } local $" = "\t"; print "@hdr\n"; print "@$_\n" for sort { $a->[1] <=> $b->[1] } @arr;

    Which will give you:

    names age Vikram 16 Binoy 19 Tushar 23 Rahul 25 Manu 36 Vijay 41 Hetal 54

    Enjoy, Have FUN! H.Merijn

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://877047]
Approved by ww
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2017-01-16 18:53 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (151 votes). Check out past polls.