Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

comment on

( #3333=superdoc: print w/replies, xml ) 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 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

In reply to Re: Trudging along the learning perl path. by Marshall
in thread Trudging along the learning perl path. by Anonymous Monk

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and the web crawler heard nothing...

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

      Results (152 votes). Check out past polls.

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