Re: Trudging along the learning perl path.by Marshall (Abbot)
|on Apr 16, 2017 at 20:42 UTC||Need Help??|
While using a hash is a preferred way to remove duplicate values, I wanted to play around with perl trying to see if it could be done without using a hash. This is what I came up with.I re-coded your idea of sorting the array and then not printing duplicates. This algorithm is going to be much slower than using a hash table, but your idea certainly works. I can tell that your brain cells were on overdrive! I hope my example will be helpful in terms of algorithmic thinking.
First a few quibbles... I changed the name of the subroutine to more accurately reflect what it does, "print the unique values". Also, in general don't push when you can print! If there is no need to save the data, then don't. Now probably this routine would have a return value in practice, but I went with what you did to illustrate this "print it!" point. I passed a reference to the @arr instead of the numbers themselves. This is just a performance tweak.
Now, to the code... Very often code isn't written in a single top down, straight line approach. I didn't do that here. First I wrote the shift statment to make clear what the interface is and to give my input param a name. Then I wrote the sort statement since I had decided to follow your approach.
Next, I decided that I was going to iterate over the @sorted array and I wrote
the loop condition, the foreach(). Next I wrote the 2 statements that comprise
the main part of the looop and embody the idea of "print this number unless I
just printed the same number". This caused me to go up to before the loop and
add the my $last_printed = undef; statement. Next, I realized that I needed
to do something special right at the beginning of the array to handle the first
number. That's when I wrote the "if" statement before the main
In loops, my advice is to write the loop conditional first... what is being interated over/what stops the loop. Next write the "main line" execution path. Then decide what to do to in order to either "get the loop started" or "fix it up" after it finishes. The print "\n"; is an example of something to do in order finalize what the loop did.
Another common pattern is to do something before the loop even starts. If I were writing this in assembly, I would do it that way because it eliminates the "if" conditional within the loop. But I am not writing assembly and a simple logical test is of no consequence (btw, the sort uses comparitively massive amounts of CPU). Also note that I did not use any indicies. The "off by one" error is the most common programming mistake and my code avoids that pitfall.
One of my hobbies is chess. I am an average player. When I play a master level player, my brain is working really, really hard and burning lots of glucose. The master level player's brain is hardly working at all! His brain is accessing patterns from thousands of previous games. Those patterns were formed by working really, really hard to figure them out. Programming is similar, patterns repeat and re-occur. It takes a lot of hard work to burn these patterns into the brain.
Don't be so hard on yourself. Practice will help form those pathways to repeating patterns. The coding process will become easier and you will become more aware of the algorithms and design of the system. Concentrate on writing clear understandable code. Forgo tricky one liners - focus on the basics.
I hope this code and my explanation of how I went about writing it is helpful to you.