Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Re: Trudging along the learning perl path.

by Marshall (Abbot)
on Apr 16, 2017 at 20:42 UTC ( #1188063=note: print w/replies, xml ) Need Help??

in reply to Trudging along the learning perl path.

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 bodypart of the loop. At that point, I could have made the code into an "if","else" construct, but I decided to just use "next;" in the if statement. I had already written what could have been the "else" clause.

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.

use warnings; use strict; my @arr = (29,24,0,24,24,12,0,0,10,10,10,19,17,15,13,1,12,12,24); sub print_uniques { my $array_ref = shift; my @sorted = sort {$a<=>$b} @$array_ref; my $last_printed = undef; foreach my $element (@sorted) { if (not defined $last_printed) # special case for 1st number { print "$element "; $last_printed = $element; next; } # do not print duplicates of the previously printed number print "$element " unless $element == $last_printed; $last_printed = $element; } print "\n"; } print_uniques(\@arr); #0 1 10 12 13 15 17 19 24 29

Replies are listed 'Best First'.
Re^2: Trudging along the learning perl path.
by Discipulus (Abbot) on Apr 16, 2017 at 21:17 UTC
    super post Marshall!

    Beside of very clean explanation of your code generation, i like the example of chess gamers: patterns are a central argument while learning.

    A second general principle come to my mind: we are what we eat

    Listening good music open your music possibilities as reading good perl code can lead to better programs. Here idiomatic perl fit well as suggestion: to recognize and to write idiomatic perl is not a way to be flattened to a monolithic usage of the language, is instead a way to collect good patterns to rearrange with creativity to solve your problems.


    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.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1188063]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2019-05-26 16:59 GMT
Find Nodes?
    Voting Booth?
    Do you enjoy 3D movies?

    Results (153 votes). Check out past polls.

    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!