Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

A Beginner Needs Homework help

by Swizzlestix617 (Novice)
on Apr 10, 2014 at 03:34 UTC ( [id://1081743]=perlquestion: print w/replies, xml ) Need Help??

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

Hi. My name's Ang and I'm new (to perlmonks and to Perl, first computer programming class) and I need help with a homework assignment. This is my homework assignment:

Consider a file consisting of lines that contain a color and an amount separated by colons, like:

red:27

yellow:102

green:311

yellow:12

blue:45

Should output (not necessarily in that order):

red:27

yellow:114

green:311

blue:45

Your program must take the input file as a parameter.

This is the code I've written:
#!/usr/bin/perl; use strict; use warnings; open (FH,$ARGV[0]) or print "could not open file" ; my $info = <FH>; while ($info=~ /(\w+ (-?\d+ )+)/) { my $info =~ s/(\w+ (-?\d+ )+)//; } my @nums = split(/:/,$info); my $word = shift (@nums); my $sum = 0; my $var = ($info); foreach $var (@nums) { $sum = $sum + $var; } my %hash = ($word = $sum); print @nums; close(FH);

These are the errors I'm getting.. and I don't understand them, how to fix them.. I feel like I'm not that good at this, so if you decide to help me explain it like I'm a kindergardener..

Argument "27 yellow" isn't numeric in addition (+) at ar991homework411 line 21, <FH> line 1. Argument "102 green" isn't numeric in addition (+) at ar991homework411 line 21, <FH> line 1. Argument "311 yellow" isn't numeric in addition (+) at ar991homework411 line 21, <FH> line 1. Argument "12 blue" isn't numeric in addition (+) at ar991homework411 line 21, <FH> line 1. Odd number of elements in hash assignment at ar991homework411 line 25, <FH> line 1.

Thanks for any help! Ang

Replies are listed 'Best First'.
Re: A Beginner Needs Homework help
by GrandFather (Saint) on Apr 10, 2014 at 04:34 UTC

    Great to see you using strictures. 'use warnings' is getting you the "Odd number of elements in hash assignment" message and that is telling you important stuff, even though it doesn't mean much to you yet. But before we get to that:

    Remove the ; from the #! line. I suspect on a *nix box that will cause you grief, although the whole line is mostly ignored by Windows.

    Use three parameter open and a lexical file handle:

    open my $fIn, '<', $ARGV[0] or ...

    You only make one assignment to $info using <FH> so you only ever read the first line from the file. Maybe there should be a while loop somewhere around there?

    The my $fIn helps strict help you. The '<' makes it clear that you want an input file handle and avoids some potential traps with the two argument version of open.

    Your while loop doesn't buy you much, especially as you create a new variable inside the loop which gets the value undef. It's fortunate (in a way) that the match controlling the loop fails for your data because otherwise you'd get a stream of using uninitialised variable warnings until you stopped the script running. What is the intent of that loop?

    I wouldn't call an array that gets a word and a number 'nums' - that just seems plain wrong. 'values' would be a better name. An even better technique is:

    my ($colour, $value) = split /:/, $info;

    The my () makes a list so you can assign the list generated by split to the list of variables created by my.

    Finally, the warning is because $word = $sum is an assignment so ($word = $sum) is a list containing the value of $sum which is probably not what you intended. However, you need to rethink the entire structure of your program. You need to loop over all the lines of the file and update colour counters as you go. A hash is the right structure for the update process so you need to keep thinking that way. Think about how you would do this if you had pieces of paper (the values) in pigeon holes (the hash) and were getting the data a line at a time over the phone.

    Have another crack at this and post the result for further comment.

    Perl is the programming world's equivalent of English
      I don't have a windows, I have a mac. Does that matter?
        "I don't have a windows, I have a mac. Does that matter?"

        I have a Mac. I start all my scripts like this:

        #!/usr/bin/env perl

        When you start using "Command Switches", you can add them after that. For example, here's one I commonly use:

        #!/usr/bin/env perl -l

        -- Ken

        Perl is pretty cross platform. The #! line is a *nix thing which may be important on a Mac as Macs these days are really *nix boxes in any case. I didn't mention Mac because Windows and *nix are by far the most common platforms for people discussing Perl and Mac is kinda a special case of *nix anyway.

        Perl is the programming world's equivalent of English

        For the most part, Mac (today) is unix-ish. Unix at its core with Apple 'tweaks'.

        --MidLifeXis

Re: A Beginner Needs Homework help
by NetWallah (Canon) on Apr 10, 2014 at 04:43 UTC
    Ok - here is a line-by-line commentary on your code. Look up the relevant documentation to fix.
    open (FH,$ARGV[0]) or print "could not open file" ; # Better to use the 3-argument version of "open", and lexical file han +dles : # open ( my $fh, "<", $ARGV[0]) or print "could not open file '$ARGV +[0]'; $!"; my $info = <FH>; # This reads ONLY the first line of the file.. # You need to put the file reading into a "while" loop that exits at E +OF # Typically, this is written : while (<$fh>){ ..do stuff .. } while ($info=~ /(\w+ (-?\d+ )+)/) # move regex stuff inside the whi +le { my $info =~ s/(\w+ (-?\d+ )+)//; # Careful with spaces inside +regexs } my @nums = split(/:/,$info); # These need to be inside the while my $word = shift (@nums); my $sum = 0; my $var = ($info); foreach $var (@nums) # Adding up stuff needs to be inside the while { $sum = $sum + $var; } my %hash = ($word = $sum); # You mean ($word => $sum) print @nums; # try print "@nums\n"; That will space out the numbers, a +nd add a newline.

            What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?
                  -Larry Wall, 1992

Re: A Beginner Needs Homework help
by InfiniteSilence (Curate) on Apr 10, 2014 at 04:17 UTC

    There's just too much wrong with your code to even begin trying to fix it. The secret to learning how to code is to do two things:

    • 1) Start small - one liners, simple regexes, etc. Don't try to write full programs before you are comfortable with the basics of the language.
    • 2) Read existing programs! Ever wonder why your English teacher gave you so much to read? Because we learn mainly via emulation and mimicry (blame it on evolution). Hence, to learn how to program you should consider reading quite a bit of existing/working code.
    Here's an example that actually works as a one liner. I'm guessing it will be unacceptable to turn a one liner in as your homework answer so you'll have to figure out how it works before rewriting it.
    E:>perl -ne "BEGIN{my %stuff = ()}; @items=split q|: |; $stuff{$items[0]} += $items[1]; END{for(keys %stuff){print qq|$_:$s +tuff{$_}\n|}};" fakedata.dat blue:45 red:27 green:311 yellow:114

    Celebrate Intellectual Diversity

      Is it really that bad :( oddly enough most of that code was given to me by the professor of the class.

      You're right that I'm uncomfortable with the language, but I don't have a choice when it comes to doing homework because that's how I'm graded.

      The reading existing programs makes sense, and I'll try to do that more. Where can I find beginner programs to read? Is there a thread for that here at perlmonks?

      Thanks for the advice, I really appreciate it.

        Just poke around this section of the Monastery. Most of the code will be way beyond you and some of it is bad, but there will be bits that will help and most of the really bad code will have follow up comments saying why it is bad, which is really better for learning from in many ways. The goodness of good code is seldom commented on, but having a "why this is bad" and a contrasting good example can help a lot in understanding the language and the way it is used.

        Perl is the programming world's equivalent of English

      I must strongly disagree with the advice to start with one-liners in perl! By all means, write full scripts, even if they fail. You will find they are a lot easier to debug using simple techniques like the judicious use of print statements and such than trying to figure out what went wrong with a one-liner.

      The fact that you are using strictures is a very good sign and they will point you to what might be wrong.

      It helps to remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.
Re: A Beginner Needs Homework help
by Discipulus (Canon) on Apr 10, 2014 at 07:40 UTC
    Hello Swizzlestix617 and welcome to the monastery,

    Follow the wise advice to read other's working code to learn from the beginning a perlish Perl, an idiomatic one. Consider to read a quite old but very usefull book: Perl Cookbook

    The cookbook approach was the best i found during my first years with Perl.

    HtH
    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: A Beginner Needs Homework help
by Anonymous Monk on Apr 10, 2014 at 07:10 UTC

    Could you do your best to write a line by line explanation of your program? You can add it as comments after each line

    If you're willing to do that, I'd be willing to help you straighten out your mental model of computer programs

      use strict; use warnings; #^^ for personal use to see where I've messed up open (FH,$ARGV[0]) || print "could not open file" ; my $info = <FH>; # ^^This opens whatever file is associates with the program # i.e - perl thisassignment documenthechooses # that file is placed into $info after it's read while ($info=~ /(\w+ (-?\d+ )+)/) { my $info =~ s/(\w+ (-?\d+ )+)//; } # Identifies the pattern in file. Identifies one or more words (\w+), +one or more #numbers(\d+),, also searches for new lines (-?) . my pro +fessor gave us this #pattern code so I might be totally wrong. I'm no +t very good with pattern yet.. my @nums = split(/:/,$info); #takes out colon where ever it may be in the $info scalar, @nums is a +array with #those values my $word = shift (@nums); # shifts first word my $sum = 0; # $sum is a empty scalar my $var = ($info); # i think $var is supposed to contain the numbers from $info foreach $var (@nums) { $sum = $sum + $var; } #this is to add the numbers together. Sum is empty, so with every new +number #that occurs it goes into sum and adds to whatever number is i +n var. i hope I'm #explaining that right. my %hash = ($word => $sum); #the new sum goes into the hash as a key and the color is in the list, + thats how #they associate with each other.. print @nums;
      Now that I've evaluated the code myself it is definitely missing things.. I just don't know how to build this kind of stuff. I'm such a novice that I had a hard time imagining how to put the pieces together.
        What does this line do  my $info =~ s/(\w+ (-?\d+ )+)//;
Re: A Beginner Needs Homework help
by Swizzlestix617 (Novice) on Apr 14, 2014 at 02:29 UTC

    Hello Perlmonks,

    Thank you again for all the advice and help you've given me on my assignment. I truly appreciated it.

    What I'm placing below is the answer that worked for me, and my system. It might still not be all that pretty, but it worked.

    *IF* the reader of this post is doing this same assignment and needed this help, I STRONGLY SUGGEST TRYING TO UNDERSTAND IT BEFORE COPYING IT. YOUR NEXT HOMEWORK ASSIGNMENT WILL NOT BE ONLINE FOR YOU, AND IT WON'T HELP YOU TO LEARN TO CODE.

    That is all. THANK YOU!!!!

    $, = " \n";

    $, is an output field separator "If defined, this value is printed between each of # print's arguments." (http://perldoc.perl.org/perlvar.html#The-Syntax-of-#Variable-Names). It is equal to a new line ( "\n"). Upon review I don't think this #was necessary.

    open (FH, $ARGV[0]) or die ("could not open file"); my @data = <FH>;

    The open command was used to open a file. ARGV is a array file in Perl that needs to be declared before you open the program (i.e. perl homework.pl data.txt) FH is the file handle (or name) given to the ARGV array. I converted FH to my @data on the next line.

    foreach my $data (@data) { $data =~ m/(\w+:-?\d+)/; my @numbers= split(/:/,$1); my $word = $numbers[0]; my $value = $numbers[1]; $myhash{$word} = $myhash{$word} + $value; }

    "The foreach loop repeats over a normal list value and sets the variable VAR to #be each element of the list in turn. If the variable is preceded with the keyword #my, then it is lexically scoped, and is therefore visible only within the loop."

    (http://perldoc.perl.org/perlsyn.html#Compound-Statements)

    This foreach loop is reading the @data scalar and matching any word from this pattern matcher:

    m/(\w+:-?\d+)/;

    m - specified that string has new line

    \w - a word character a-z

    + = match one or more of previous word

    :-? = i am not clear on this unfortunately

    \d = any digits 0-9

    + = match one or more of previous number.

    The array's name is changed to my @numbers and we're splitting the : out of the array. my $word is a empty scalar, and my $value is any number that was a previous value from the array. if the words match the numbers will be added #together and placed in the empty hash table. The hash table is like a legend, to read more about them look here (http://www.tutorialspoint.com/perl/perl_hashes.htm)

    while(my($key, $value) = each %myhash){ print $key . ":" . $value . "\n"; }

    this while loop goes through the hash and places a colon in between the new $key value and new $value so when the program prints the results is looks the same as the original.

    close (FH);
    this closes the file you opened.

    I placed numerous links above because I might not be the best at explaining, and these websites are fantastic. Read the comments I've gotten and try your best to continue learning. I'm finding a book by o'reilly called 'Perl in a nutshell' to also be incredibly helpful.

    link to 'Perl in a nutshell': http://www.amazon.com/Perl-Nutshell-Desktop-Quick-Reference/dp/0596002416

    THANK YOU (and good luck for future perlies) <3

      And here it is cleaned up a little:

      #!/usr/bin/perl use strict; use warnings; my %myhash; open my $fIn, '<', $ARGV[0] or die "could not open '$ARGV[0]': $!\n"; while (defined (my $line = <$fIn>)) { my ($word, $value) = $line =~ m/(\w+):(-?\d+)/; $myhash{$word} += $value; } while (my ($key, $value) = each %myhash) { print "$key: $value\n"; }

      Prints:

      green: 311 blue: 45 red: 27 yellow: 114

      Not the following changes:

      1. Use 3 parameter open: open my $fIn, '<', $ARGV[0]
      2. die not print for failure - there's no point continuing.
      3. Show the file and error in the failure message - it's easier to figure out what went wrong.
      4. Don't "slurp" the file contents into an array - use a while loop and handle the data a line at a time. The code is clearer, shorter and has less memory overhead (although the last is not usually an issue).
      5. Use the regular expression match to extract the interesting data into named variables.
      6. Use += to update the hash values. This avoids the "Use of uninitialized value in addition" the first time each new colour is added (and it's a whole lot shorter).
      7. Take advantage of Perl's string interpolation to clean up the print: print "$key: $value\n";

      Note that "short code" is not an end in itself, but the fewer (sensible) lines of code you have generally the easier it is to understand and maintain the code.

      Perl is the programming world's equivalent of English
Re: A Beginner Needs Homework help
by Lennotoecom (Pilgrim) on Apr 11, 2014 at 09:30 UTC
    /:/ and $h{$`} += $' for <DATA>; print "$_:$h{$_}\n" for sort keys %h; __DATA__ red:27 yellow:102 green:311 yellow:12 blue:45 red:1 blue:2 green:13

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1081743]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (8)
As of 2024-04-24 10:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found