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

Hey perlmonks,

as an exampel, let's consider this number "1234567890". In my script, this number is saved in a variable, and now, I wanna check, if a single number like 1 is unique in this number.

Exist a function for tasks like this?

Thanks in advance.

2006-08-10 Retitled by planetscape, as per Monastery guidelines

( keep:2 edit:22 reap:0 )

Original title: 'Unique charakter in a string?'

Replies are listed 'Best First'.
Re: Unique character in a string?
by Limbic~Region (Chancellor) on Aug 09, 2006 at 20:20 UTC
    Anonymous Monk,
    There is no built-in that will tell you if a character is unique in a string but it is easy enough to create one.
    my $cnt = $str =~ tr/1//;
    The thing to consider is that it may be better to trade space for time if you have many such tests on a given string.
    my %char_cnt; ++$char_cnt{$_} for split //, $str;
    There are a number of other solutions depending on what your situation is.

    Cheers - L~R

Re: Unique character in a string?
by imp (Priest) on Aug 09, 2006 at 20:31 UTC
    The answer to your question depends on whether you are checking whether '1' is unique, or checking for a list of unique values. If you want a list of unique characters here is one approach:
    use strict; use warnings; my $a = '12345678901'; # Create a hash which has a count of the number # of times a character appears in the string. my %tally; $tally{$_}++ for split '', $a; # # Find hash keys that only have 1 match # my @unique = grep {$tally{$_} == 1} keys %tally; print "Unique keys:\n"; print "$_\n" for sort @unique;
    And at this point if you want to check whether a particular character is unique you could do this:
    if ($tally{2} == 1) { print "2 is unique\n"; }
    If you are only looking to check for a particular character, then you can count the characters like this:
    my $a = '12345678901'; my $cnt = $a =~ tr/1//; #In this case $cnt = 2, which means it is not unique
Re: Unique character in a string?
by duckyd (Hermit) on Aug 09, 2006 at 20:24 UTC
    There's no function for this exactly that I know of, but it's trivial to get counts per character that you can use for this purpose:
    my $string = '123456789012345'; my %counts ; $counts{ $_ }++ for split //, $string; foreach my $char ( keys %counts ){ if( $counts{ $char } > 1 ){ print "$char is not unique in $string\n"; }else{ print "$char is unique in $string\n"; } }
Re: Unique character in a string?
by GrandFather (Saint) on Aug 09, 2006 at 20:42 UTC

    Or if the question you want to answer is "Is there a character that is repeated within the string?" then you can:

    print "'$1' repeated\n" if "12345617890" =~ /(.).*?\1/;

    Prints:

    '1' repeated

    DWIM is Perl's answer to Gödel
Re: Unique character in a string?
by BrowserUk (Patriarch) on Aug 09, 2006 at 20:45 UTC

    If you want to determine if a given character is unique then you could use

    if( $var =~ m[1] and $var !~ m[1.*1] ) { ## $var contains exactly one '1' character. }

    Alternatively, if you want to know if the string contains no duplicates of any character then

    if( $var !~ m[(.).*\1] ) { ## $var contains no duplicate characters }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Unique character in a string?
by swampyankee (Parson) on Aug 09, 2006 at 20:59 UTC

    Similar questions have been asked quite a few times. (More bluntly, Try a [id://Super Search|little research] first.).



    One way (probably the best) is to use the uniq function from List::MoreUtils. This is used something like this:

    use List::MoreUtils;
    use strict;
    use warnings;
    my @string = qw(a a a a b b b c d e f q q q r r r);
    my @singletons = uniq(@string);

    > where @singletons is a list of the elements in @string which occur only once. Note, however, that this operates on lists, not strings, so you'll have to split the string.

    One A second way (guaranteed to be non-optimal &grin;) is to split the string into an array and count the occurences of each character.

    use strict;use warnings; # because it's a really good idea my @string = split(//, 'aabbccddeeffgghhi'); my %count; foreach(@string) { $count{$_} ++; } foreach (keys(%count)) { print "$_ is unique\n" if $count{$_} == 1; }

    I'm quite sure some of the regex gurus can do it with a single regex; I tend more to the "brute force and ignorance"™ school of programming than the "subtle and brilliant" school.


    added in another update

    As Hofmator pointed out, I screwed up: uniq doesn't return a list of elements that occur once in the original list; it returns a list with duplicates stripped out. That's why I've struck out a much of this post.

    added in update

    I knew that somebody would find a one-line solution.

    emc

    Experience is a hard teacher because she gives the test first, the lesson afterwards.

    Vernon Sanders Law
      my @string = qw(a a a a b b b c d e f q q q r r r); my @singletons = uniq(@string);
      where @singletons is a list of the elements in @string which occur only once.
      This is not true, uniq removes duplicates from an array. From the doc:
      uniq LIST Returns a new list by stripping duplicate values in LIST. The order of elements in the returned list is the same as in LIST. In scalar context, returns the number of unique elements in LIST. my @x = uniq 1, 1, 2, 2, 3, 5, 3, 4; # returns 1 2 3 5 4

      -- Hofmator

Re: Unique character in a string?
by johngg (Canon) on Aug 09, 2006 at 23:21 UTC
    You can use a look-ahead like this

    use strict; use warnings; my $str = q{abcdceefghfty}; for my $ch (qw(a b c d e f g)) { print qq{"$ch" Unique in "$str"\n} if $str !~ m{($ch)(?=.*\1)}; }

    which produces

    "a" Unique in "abcdceefghfty" "b" Unique in "abcdceefghfty" "d" Unique in "abcdceefghfty" "g" Unique in "abcdceefghfty"

    Cheers,

    JohnGG

    Update: The above approach is flawed in that testing for a character that doesn't occur in the string at all would still succeed and show as unique. This is because testing that the string doesn't match multiple characters is also true if there are no characters.

    The amended script below changes by looking for positive matches of a single character. It is a touch more complex because of the need to interpolate the character being sought into a negated character class, hence the qr{...}. Looking for a hard-coded character is simpler, e.g. to check that "c" was unique, $str =~ m{\A[^c]*(c)(?!.*\1)} would work. Here's the amended script.

    use strict; use warnings; my $str = q{abcdceefghfty}; for my $ch (q{a} .. q{z}) { my $matchTxt = q {\A} . qq{[^$ch]*($ch)} . q {(?!.*\1)}; my $rxUniq = qr{$matchTxt}; print qq{"$ch" unique in "$str"\n} if $str =~ $rxUniq; }