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

Good afternoon Monks of Wisdom, I am struggling with a piece of coding that is required for my school assignment. The assignment is set to count the number of characters as well as unique characters. If I entered in - Perl Monks Rocks!!! I should get 19 characters total with 3 unique characters. I have no clue as to how to find the unique characters. This is what I have thus far, and any help is greatly appreciated.
print "Enter an input string: "; chomp (my $str = <STDIN>); print "Input String: $str\n"; my $cnt = @{[$str =~ /./sg]}; print "Total characters (including spaces & punctuation): $cnt\n"; print "Unique Characters (including spaces & punctuation): \n";

Replies are listed 'Best First'.
Re: Unique Character
by Kenosis (Priest) on Feb 01, 2014 at 19:31 UTC

    Kudos to you for being up front about this being a school assignment!

    Will provide the mechanism that's typically used for this, so you can work it out...

    In such cases, a hash is usually used to tally unique characters/words/phrases, as keys of the hash. It's important to convert the characters to all upper- or lower-case, before using them as a key.

    For example, converting the characters of "Perl Monks Rocks!!!" to all upper-case, your hash (e.g., %hash), could contain (could because of the algorithm you finally choose) the following key/value pair:

    'O' => 2

    Note that "O" has a count of 2. Getting the number of the hash's keys will give you a count of the unique characters--provided they're all the same case. Summing all the hash's values will give you the total number of characters.

    Now, having said all this, how is it that the string in question has only three unique characters? What is the character property used such that only three would be considered unique? If it's being upper-case, you can still use a hash (e.g., with the keys "upper" and "other"), but with a regex that would distinguish between upper-case and all other characters.

    A separate item: always, at the top of your scripts:

    use strict; use warnings;

    Doing so will likely save you many headaches...

    Hope this helps!

Re: Unique Character
by davido (Cardinal) on Feb 01, 2014 at 22:18 UTC

    I know you stated the correct value for the "character count" attribute with the text sample you provided is nineteen, which is what people would usually refer to as the length of the string.

    Another characteristic is how many characters are used one or more times. I would call this the number of unique characters, but you use the term "unique" for a different purpose (see below), and it appears that this isn't a characteristic you're supposed to be deriving.

    Then there's the number of characters that occur only once. You call that unique. I might consider that non-repeated characters. But it doesn't really matter what we call things as long as we understand each other. I'm going to understand that you need a total of how many characters the string contains (its length), and a count of how many characters occur exactly one time within the string (your 'unique' attribute).

    In Perl, the easiest way to derive a string's length is with the length function. But if you're looking for another way, yours works, though it's probably better suited for obfuscation, and I'm sort of surprised to see it show up in a solution for a starting course. Has your course really gotten into references already?

    To satisfy your definition of "unique characters", iterate over every character in the string, and increment a hash element with that character as a key. Then look at the keys of your hash, and the values they index. Anytime you come across a value of '1', you know that letter appeared only once, and you can increment a "unique chars" counter.

    I'm still a little concerned about your definition of unique characters. I wonder if you've misunderstood, and really need to count how many characters appear at least one time. That's actually a little easier: Use the hash approach, but instead of only counting keys that index a value of exactly one, just tally up how many keys you have.

    The second part, whether it's "characters that appear exactly once", or "characters that appear one or more times", you will find keys useful. Also look over perlfaq4, "How can I get the unique keys from two hashes, just as an example of using hashes to reduce lists of items to unique components.


    Dave

Re: Unique Character
by Laurent_R (Canon) on Feb 01, 2014 at 20:08 UTC
    Kenosis has given you some clues (using a hash) on how to count each different character. For the total character count, your approach:
    my $cnt = @{[$str =~ /./sg]};
    probably works, but seems too complicated (and slow, when that matters). Take a look a the length function.

      Indeed, length would be the most straight forward here.

Re: Unique Character
by ww (Archbishop) on Feb 02, 2014 at 00:11 UTC

    We agree that there are 19 characters in the string... but your definition/usage of "unique" is indeed made very fuzzy when you say "I should get 19 characters total with 3 unique characters." I don't see how you get there:

    arabic digit indicates instance of a char' "x" indicates no repetition/dupe (6); and roman numerals indicate distinct repeated chars (VI) AT THE FIRST +REPEAT my $str = "PERL MONKS ROCKS!!!"; P 1 x E 1 x R 1 I L 1 x 1 repeated later M 1 x O 1 repeated later N 1 x K 1 repeated later S 1 repeated later 2 II R 2 I O 2 III C 1 X K 2 IV S 2 V ! 1 VI ! 2 VI ! 3 VI
    Come, let us reason together: Spirit of the Monastery
      Thanks for pointing that out to me ww about the unique characters. I used my phone a friend, and they explained to me what my professor wants. The unique characters he wants is how often a character is repeated. Such as if I used Jim Doe. There would be a total of 8 unique characters. If I used John Doe. there would still be 8 unique characters due to the o was already counted.
        This will do the trick:
        use Modern::Perl; my $string = "Perl Monks Rocks!!!"; my %chars; for ( split '', $string ) { $chars{ lc $_ }++ } my @uniques = sort keys %chars; say scalar @uniques, ": @uniques";

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

        My blog: Imperial Deltronics