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

New to perl so I decided to start with something simple, I'm attempting to create a simple anagram generator (without cheating by looking at other code). I have a text file dictionary that I'm trying to use to fill a hash. I tested it first with an array and it worked just fine. However when I try to fill a hash with it it fails to enter any keys or values for that hash.
#!usr/local/bin/perl my $userinput = "myexample"; my $wordfile = '/home/psychohamster/Desktop/Desktop_Stuff/AnagramWordL +ist'; my $wordcount = 0; my $deadstring = ""; my %hashlist = (); open my $wordhandle, $wordfile or die "Unable to open WordList: $!"; while (<$wordhandle>) { $deadstring = chomp; $hashlist{$deadstring} => 1; $wordcount++; } $wordcount -= 1; if (!%hashlist) { print "Empty\n"; } else { print "Not Empty\n"; }
The last print statement always returns empty, now if i put a Key and a value in the hash declaration it will accept it. I just can not add any more hashes after run time. What am I missing?

Replies are listed 'Best First'.
Re: Attempting to fill a hash
by pc88mxer (Vicar) on Jun 06, 2008 at 00:32 UTC
    You want to change:
    while (<$wordhandle>) { $deadstring = chomp; $hashlist{$deadstring} => 1; $wordcount++; }
    to:
    while (<$wordhandle>) { chomp; $hashlist{$_} = 1; $wordcount++; }
    You had two small errors...

    1. chomp returns the number of characters chomped, so $deadstring = chomp assigns a number to $deadstring.

    2. You're using the fat comma => instead of the assignment operator = in $hashlist{$deadstring} => 1;.

      First off, thank you pc88. That does finally get the hash to fill out where it admits not empty, but for some reason I can't pull up any values. The very first line in the text file is 'a' and the line print "$hashlist{a}\n"; which should display 1, simply prints a newline character as if it couldn't find the key named a EDIT* - i assigned the %hashlist to an @array, and when I print the first couple $array it displays completely unexpected values, is there a limit to the size of a default hash that I could be overflowing it (109,000) entries in the text file p.s. that makes perfect sense about the way i had chomp assigned, that's what I get for using VB for so long.
        I would add:
        use Data::Dumper; print Dumper(\%hashlist);
        to see what %hashlist contains. That will probably clarify a lot of things.
        Based on your Data::Dumper output it is clear that you still have newlines at the end of your hash keys. Are you sure you are doing:
        chomp; $hashlist{$_} = 1;
        or do you have something else?
Re: Attempting to fill a hash
by GrandFather (Saint) on Jun 06, 2008 at 01:11 UTC

    There are a few style related things that may help. First, always use strictures (use strict; use warnings;). They give an early warning about a number of common types of error.

    You hardly ever need to explicitly count things in Perl so you don't need to maintain $wordcount in the loop.

    Always use the three parameter open. It's safer and explicit about the open mode. Good to see you testing the open result by the way!

    Keep variables as local as possible. Note in the sample below that $deadstring is local to the loop (why that name btw?).

    Your off by one in $wordcount was probably due to a blank line. Better to test for that in the loop.

    Here's a reworked version of your code. Note that the "file" is actually a string variable. That's a really useful trick for samples like this so you don't need a "real" file.

    use strict; use warnings; my $wordlist = <<WORDS; a the cat mat sat WORDS my $userinput = "myexample"; my $wordfile = '/home/psychohamster/Desktop/Desktop_Stuff/AnagramWor +dList'; my %hashlist; open my $wordhandle, '<', \$wordlist or die "Unable to open WordList: +$!"; while (my $deadstring = <$wordhandle>) { chomp $deadstring; next unless length $deadstring; $hashlist{$deadstring} = 1; } my $wordCount = keys %hashlist; if ($wordCount) { print "Found $wordCount words:\n"; print join "\n", sort keys %hashlist, ''; } else { print "Didn't find any words\n"; }

    Prints:

    Found 5 words: a cat mat sat the

    Perl is environmentally friendly - it saves trees
      GrandFather,
      Thank You.
      First off thank you for that little tip on word lists, very nice.
      Two things
      1. next unless length $deadstring; - I'm assuming this is to make sure that $deadstring is not an empty variable.
      2. Worked perfectly when I tried it with the word list. However, once I tried using the actual file, it started reading the data wrong again. Is it possible that the coding of the file is causing the streamreader to interpert it wrong for perl?

        next unless length $deadstring; uses a statement modifier (the unless bit) which is rather like an if statement backwards. You can use if, unless, for and while as statement modifiers.

        Try copying and pasting from your file into the sample code where the word list is. If that shows the error you see with the real file then post the modified sample here. If it doesn't show the same error then most likely your editor is modifying the text somewhat. One possibility is that the file has different line endings than are native on your system. For example, you may have got the file from a *nix system and are running it under Windows or vis-versa.


        Perl is environmentally friendly - it saves trees
Re: Attempting to fill a hash
by toolic (Bishop) on Jun 06, 2008 at 01:19 UTC
    Perhaps a small, complete example (with embedded comments) will help:
    % cat AnagramWordList foo bar baz % cat 690557.pl #!/usr/bin/env perl use strict; use warnings; my $wordfile = 'AnagramWordList'; my %hashlist; ### It is a good practice to use the 3-argument form of "open" open my $wordhandle, '<', $wordfile or die "Unable to open WordList: $ +!"; while (<$wordhandle>) { chomp; ### Remove newline character $hashlist{$_}++; ### Add word to hash } close $wordhandle; ### It is a good practice to close the file AS +AP ### Print out contents of hash while (my ($key, $value) = each %hashlist) { print "key=$key, value=$value\n"; } % ./690557.pl key=bar, value=1 key=baz, value=1 key=foo, value=1
      Thank you for your assistance.
      I believe I have finally cracked the problem. The file I was using was downloaded, and evidently there is some kind of character attached to the words that is messing up either chomp or reading it period. When I delete a word manually in gedit and retype it then save the file. That word will succesfully load a keyvalue, however all the other words won't. I'm going to attempt to read all the lines into an array and write them back as raw data to fix the file.

        Your file has most likely been written on Windows, and you're reading it on Unix...  You could run

        $ perl -i.bak -pe 's/\r$//' your-wordlist.file

        to remove the extraneous carriage returns.

        Alternatively, filter the file through the crlf PerlIO layer when reading it (as it does happen on Windows by default), i.e.

        open my $wordhandle, "<:crlf", $wordfile or die ...
Re: Attempting to fill a hash
by jwkrahn (Abbot) on Jun 06, 2008 at 00:25 UTC

    You want to change:

    while (<$wordhandle>) {

    To:

    while (my $deadstring = <$wordhandle>) {
      that still gave me an empty hash, the problem is not reading the text from the file (I successfully filled out an array using the same code) It's just that when I try to put into the hash it fails. Am i using the right method to edit the hash after it's already been declared.

      Why?

      chomp will work on the underinitialized $_, and that assignment line will assign effectively zero to $deadstring. How will that help?