Abhisek has asked for the wisdom of the Perl Monks concerning the following question:

Will this be able to create a hash with $keys as the content of each line of the input file and values as the number of lines ($linecount)
#!/usr/bin/perl -w open(IN,"$infile1") or die "Can't open $infile1" $linecount= 0; %hash = 0; while (my $line=<IN>) { $linecount=$linecount+1; push(@{$hash{$line}},$linecount); }

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

Replies are listed 'Best First'.
Re: hash values
by GrandFather (Saint) on Feb 08, 2008 at 07:10 UTC

    The outline of your code is sorta correct. The details show a few errors and chances for cleaning up. First, consider your code as reformatted by Perl Tidy:

    #!/usr/bin/perl -w open( IN, "$infile1" ) or die "Can't open $infile1" $linecount = 0; %hash = 0; while ( my $line = <IN> ) { $linecount = $linecount + 1; push( @{ $hash{$line} }, $linecount ); }

    You may notice that the second line has a little more on it than you might first expect: you've omitted a semicolon.

    Staying with the second line: it is much better to use the three parameter version of open: open IN, '<', $infile1 .... Checking the result with die is great, but you get more mileage from it if you report the actual error: ... die Can't open $infile1: $!";.

    On line three you declare a hash using my - great stuff. However you don't need to assign anything to the hash to "initialize" it. Just my %hash; is just perfect in this case.

    The while loop header on line four is just right.

    Perl provides the special variable $. ($INPUT_LINE_NUMBER) that provides the line number of the most recently read line. Use that instead of maintaining your own line number count - if you actually need that count at all.

    Line six is the key to the whole script. It adds the current line number to an array referenced by an entry in the hash keyed by the contents of the current line - not quite what you imply in your description, but fairly likely what you intend. Using the special variable line six can be cleaned up a little:

    push @{ $hash{$line} }, $.;

    However, now there is only one statement inside the while loop and that suggests that the while could be turned into a statement modifier. Consider:

    push @{ $hash{$_} }, $. while <IN>;

    and finally, it is good practice to close all file handles that you opened:

    close IN;

    Perl is environmentally friendly - it saves trees
      This is a really good post. You might consider adding a bit more to it and making it a newbie tutorial.

      Celebrate Intellectual Diversity

Re: hash values
by mhearse (Chaplain) on Feb 08, 2008 at 06:11 UTC
    You might be better of using the line count as the key, and line text as value...
    #!/usr/bin/perl use strict; open IN, "$infile1" or die $!; my $linecount = 0; my %hash; while (my $line = <IN>) { chomp $line; $linecount+=1; $hash{$linecount} = $line; }
Re: To assign values to a Hash
by poolpi (Hermit) on Feb 08, 2008 at 07:22 UTC
    $ cat infile1.txt line1 line3 line2 line1 line3 line4 line2
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hash; my $myfile = '/dir/subdir/infile1.txt'; open( my $in, '<', $myfile) or die "Can't open $myfile: $!"; map { chomp; $hash{ $_ }++ } <IN>; close($in); print Dumper \%hash;
    Output: $VAR1 = { 'line3' => 2, 'line2' => 2, 'line4' => 1, 'line1' => 2 };

    hth,

    PooLpi

    Update : chomp
Re: To assign values to a Hash
by graff (Chancellor) on Feb 08, 2008 at 09:37 UTC
    I think poolpi has answered the question as you stated it: show a count of how many times each distinct full-line string appears in a file. But your first attempt, trying to store a hash of arrays, made me think that maybe you want more information besides the number of occurrences.

    The HoA thing would be useful if you wanted to keep track of the line numbers where each distinct full-line string appears. The number of occurrences per string is then just the number of elements in the array for that string:

    #!/usr/bin/perl use strict; my %hash; push( @{$hash{$_}}, $. ) while (<>); print "Total\tLocations\tString\n"; # output a header line printf( "%d\t%s\t%s", scalar(@{$hash{$_}}), join(",",@{$hash{$_}}), $_ ) for ( sort keys %hash );
    (updated to fix grammar in first paragraph)
Re: To assign values to a Hash
by bruceb3 (Pilgrim) on Feb 08, 2008 at 06:37 UTC
    I thinking that a couple of changes are needed (untested).
    #!/usr/bin/perl -w use strict; # for some value of $infile1 open (IN, "$infile1") or die "can't open $infile1"; my $linecount = 0; $hash{$line} = $linecount++ while (<IN>); close IN;
      I'm thinking you may have misunderstood the OP. For each distinct full-line text pattern in the file, the desired hash value is "the number of lines" -- i.e. how many times the given text pattern occurs as a line in the file. (See the following reply from poolpi.)

      Apart from that, there are problems with your suggested code. It looks like your idea is for the hash value to be the line number in the file where a given text pattern is last seen, but you are post-incrementing $linecount when assigning it to each hash element (so the first line of the file is line number 0 instead of 1), and it won't work anyway, because you use "$line" as the hash key without ever assigning anything to $line -- in fact, if you tried "perl -cw" on your script as originally posted, it won't compile because $line is never declared.

      (Lot's of monks post untested code and that's fine, but as a rule, when posting any snippet that includes "use strict;", you should at least pass it through "perl -cw" first to see whether it compiles.)

      Update: by the way, to implement your idea (store the last line number containing a given text pattern), you don't need any variables other than the hash (and maybe the file name, but probably not even that):

      #!/usr/bin/perl use strict; my %hash; $hash{$_} = $. while (<>); print "$hash{$_} : $_" for (sort {$hash{$a}<=>$hash{$b}} keys %hash);