I came upon this question, because it seems to be very common use-case to find unique characters in string. But what if we want to get rid of them?

Input contains only lower case alphabets. Only letters from a to z are used. Input length may be from 1 to 1000 characters.

Example:
input: helloworld
output: llool

Objective: Shortest code wins
Language: Any of the top 20 of TIOBE languages

18 Answers 18

up vote 7 down vote accepted

Perl, 28 24 characters (includes 1 for 'p' option)

s/./$&x(s!$&!$&!g>1)/eg

Usage:

> perl -pe 's/./$&x(s!$&!$&!g>1)/eg'
helloworld
llool

At first I thought I could do this with negative look-ahead and negative look-behind, but it turns out that negative look-behinds must have a fixed length. So I went for nested regexes instead. With thanks to mob for the $& tip.

  • +1. I naively thought I could take this thing with my Ruby answer. – Steven Rumbalski Oct 11 '12 at 14:27
  • i tried this on chinese text and it did not do the trick. =( – ixtmixilix Oct 12 '12 at 0:12
  • @ixtmixilix - then run perl with the -CDS option – mob Oct 12 '12 at 0:38
  • @ixtmixilix I don't know enough about unicode and Perl's support of it to suggest a way to make it work with chinese text I'm afraid. Luckily for me the question says only lower case a to z. – Gareth Oct 12 '12 at 0:38
  • 1
    Replace all the $1 with $& and you can lose a couple pairs of parentheses. – mob Oct 12 '12 at 0:39

(GolfScript, 15 13 characters)

:;{.;?);>?)},

GolfScript is not one of the top 20, but a codegolf without GolfScript... (run it yourself)

Previous Version: (run script)

1/:;{;\-,;,(<},
  • :;? You're deliberately trying to confuse newbies, aren't you? ;) – Peter Taylor Oct 11 '12 at 9:17
  • @PeterTaylor You're right. I should have chosen a ) - it would make it a smiley then :). Unfortunately, I didn't find a way to even eliminate the digit 1. (Note for GolfScript newbies: you may replace any ; in the code with a x (or any other letter or digit - or any character not used in the script otherwise). In this special case ; is just a variable name - and has not the meaning "pop and discard". In GolfScript almost all tokens are variables anyways, and using predefined symbols is great way to make scripts even more unreadable for outsiders ;-).) – Howard Oct 11 '12 at 11:09
  • Another 13-char solution: :a{]a.@--,(}, – Ilmari Karonen Apr 11 '14 at 19:01

J, 12 characters

Having entered a valid Perl answer, here's an invalid (language not in the TIOBE top 20) answer.

a=:#~1<+/@e.

Usage:

   a 'helloworld'
llool

Declares a verb a which outputs only non unique items.

GolfScript (14 chars)

:x{{=}+x\,,(},

Online demo

Might not qualify to win, but it's useful to have a yardstick.

Ruby 46 40 36

gets.chars{|c|$><<c if$_.count(c)>1}
  • You may save 4 chars if you inline s and use $_ for the second appearance (the space before is then dispensable). – Howard Oct 11 '12 at 11:22
  • @Howard: Nice catch. Thanks. I have about zero experience with Ruby. – Steven Rumbalski Oct 11 '12 at 14:03

Perl 44

$l=$_;print join"",grep{$l=~/$_.*$_/}split""

Execution:

perl -lane '$l=$_;print join"",grep{$l=~/$_.*$_/}split""' <<< helloworld
llool

K, 18

{x@&x in&~1=#:'=x}

Python 2.7 (52 51), Python 3 (52)

I didn't expect it to be so short.

2.7: a=raw_input();print filter(lambda x:a.count(x)>1,a)

3.0: a=input();print''.join(i for i in a if a.count(x)>1)

raw_input(): store input as a string (input() = eval(raw_input()))
(Python 3.0: input() has been turned into raw_input())

filter(lambda x:a.count(x)>1,a): Filter through all characters within a if they are found in a more than once (a.count(x)>1).

  • If you use python 3 instead, you can use input() rather than raw_input(). Although you have to add one character for a closing bracket, since print is a function in python 3. – Strigoides Oct 16 '12 at 2:03
  • @Strigoides: I have added a Python 3 code snippet to my answer. – beary605 Oct 16 '12 at 2:18
  • Python 3's filter returns an iterator... You'll need to do ''.join(...) – JBernardo Oct 16 '12 at 4:23
  • @JBernardo: :( Dang. Thanks for notifying me. As you can see, I don't use 3.0. – beary605 Oct 16 '12 at 5:20

Python (56)

Here's another (few chars longer) alternative in Python:

a=raw_input();print''.join(c for c in a if a.count(c)>1)

If you accept output as a list (e.g. ['l', 'l', 'o', 'o', 'l']), then we could boil it down to 49 characters:

a=raw_input();print[c for c in a if a.count(c)>1]
  • Hey, >1 is a good idea! May I incorporate that into my solution? – beary605 Oct 11 '12 at 2:32
  • @beary605 Sure no problem at all - easy way to trim a character off :D – arshajii Oct 11 '12 at 2:43

Ocaml, 139 133

Uses ExtLib's ExtString.String

open ExtString.String
let f s=let g c=fold_left(fun a d->a+Obj.magic(d=c))0 s in replace_chars(fun c->if g c=1 then""else of_char c)s

Non-golfed version

open ExtString.String
let f s =
  let g c =
    fold_left
      (fun a c' -> a + Obj.magic (c' = c))
      0
      s
  in replace_chars
  (fun c ->
    if g c = 1
    then ""
    else of_char c)
  s

The function g returns the number of occurences of c in the string s. The function f replaces all chars either by the empty string or the string containing the char depending on the number of occurences. Edit: I shortened the code by 6 characters by abusing the internal representation of bools :-)

Oh, and ocaml is 0 on the TIOBE index ;-)

  • f*** the TIOBE index. – ixtmixilix Oct 12 '12 at 0:04
  • I agree. Also, thanks for the upvote. Now I can comment :-) – ReyCharles Oct 12 '12 at 0:17

sed and coreutils (128)

Granted this is not part of the TIOBE list, but it's fun (-:

<<<$s sed 's/./&\n/g'|head -c -1|sort|uniq -c|sed -n 's/^ *1 (.*)/\1/p'|tr -d '\n'|sed 's:^:s/[:; s:$:]//g\n:'|sed -f - <(<<<$s)

De-golfed version:

s=helloworld
<<< $s sed 's/./&\n/g'        \
| head -c -1                  \
| sort                        \
| uniq -c                     \
| sed -n 's/^ *1 (.*)/\1/p'   \
| tr -d '\n'                  \
| sed 's:^:s/[:; s:$:]//g\n:' \
| sed -f - <(<<< $s)

Explanation

The first sed converts input into one character per line. The second sed finds characters that only occur once. Third sed writes a sed script that deletes unique characters. The last sed executes the generated script.

Mathematica 72 63

Ok, Mathematica isn't among the top 20 languages, but I decided to join the party anyway.

x is the input string.

"" <> Select[y = Characters@x, ! MemberQ[Cases[Tally@y, {a_, 1} :> a], #] &]

Perl (55)

@x=split//,<>;$s{$_}++for@x;for(@x){print if($s{$_}>1)}

Reads from stdin.

C# – 77 characters

Func<string,string>F=s=>new string(s.Where(c=>s.Count(d=>c==d)>1).ToArray());

If you accept the output as an array, it boils down to 65 characters:

Func<string,char[]>F=s=>s.Where(c=>s.Count(d=>c==d)>1).ToArray();

PHP - 137

Code

implode('',array_intersect(str_split($text),array_flip(array_filter(array_count_values(str_split($text)),function($x){return $x>=2;}))));

Normal Code

$text   = 'helloworld';
$filter = array_filter(array_count_values(str_split($text)), function($x){return $x>=2;});
$output = implode('',array_intersect(str_split($text),array_flip($filter)));

echo $output;

PHP - 83 78

<?for($a=$argv[1];$i<strlen($a);$r[$a[$i++]]++)foreach($ras$k=>$c)if($c>1)echo$k

Improved version:

<?for($s=$argv[1];$x<strlen($s);$c=$s[$x++]) echo substr_count($s,$c)>1?$c:'';

Of course this needs notices to be turned off

Edit: Improvement inspired by @hengky mulyono

I am so bad at codegolf :)

PHP - 70

while($x<strlen($s)){$c=$s[$x];echo substr_count($s,$c)>1?$c:'';$x++;}

with asumption $s = 'helloworld'.

Java 8, 90 bytes

s->{for(char c=96;++c<123;s=s.matches(".*"+c+".*"+c+".*")?s:s.replace(c+"",""));return s;}

Explanation:

Try it online.

s->{                         // Method with String as both parameter and return-type
  for(char c=96;++c<123;     //  Loop over the lowercase alphabet
    s=s.matches(".*"+c+".*"+c+".*")?
                             //   If the String contains the character more than once
       s                     //    Keep the String as is
      :                      //   Else (only contains it once):
       s.replace(c+"",""));  //    Remove this character from the String
  return s;}                 //  Return the modified String

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.