Given a string consisting of printable ASCII chars, produce an output consisting of its unique chars in the original order. In other words, the output is the same as the input except that a char is removed if it has appeared previously.

No built-ins for finding unique elements in an array can be used (for example, MATLAB has a unique function that does that). The idea is to do it manually.

Further details:

  • Either functions or programs are allowed.
  • Input and output can be in the form of function arguments, stdin/stdout (even for functions), or a mix of those.
  • If stdin or stdout are used, a string is understood as just the sequence of chars. If function arguments are used, the sequence of chars may need to be enclosed in quotation marks or equivalent symbols that the programming language of choice uses for defining strings.
  • The output should be a string containing only the unique characters of the input. So no extra linebreaks, spaces etc. The only exception is: if the output is displayed in stdout, most displaying functions add a trailing \n (to separate the string from what will come next). So one trailing \n is acceptable in stdout.
  • If possible, post a link to an online interpreter/compiler so that others can try your code.

This is code golf, so shortest code in bytes wins.

Some examples, assuming stdin and stdout:

  1. Input string:

    Type unique chars!

    Output string:

    Type uniqchars!
  2. Input string

    "I think it's dark and it looks like rain", you said

    Output string

    "I think'sdarloe,yu
  3. Input string


    Output string

  • 5
    \$\begingroup\$ Just to double check: Does the no builtins rule mean that set objects are disallowed? \$\endgroup\$ – Sp3000 Oct 4 '15 at 14:51
  • \$\begingroup\$ @Sp3000 Set objects are allowed. Just don't use a function or method (if it exists) that gives you its unique elements. And input/output should be strings, not set tobjects \$\endgroup\$ – Luis Mendo Oct 4 '15 at 14:54
  • \$\begingroup\$ @Sp3000 Do you think it would make it more interesting to reduce byte count by half if no set functions are used? Or better not change the rules once the challenge has been set? \$\endgroup\$ – Luis Mendo Oct 4 '15 at 15:08
  • 5
    \$\begingroup\$ I think only my answer uses sets currently, and I wouldn't mind if you changed it. However, I'm not really sure a bonus like that would change much, e.g. I doubt CJam would be doable in < 6 bytes without sets. Also, I'm not sure where the line is between a builtin which finds unique elements, and constructing a set from a number of elements... \$\endgroup\$ – Sp3000 Oct 4 '15 at 15:13
  • 1
    \$\begingroup\$ @Sp3000 Yes, it's a blurred border. I hadn't anticipated set functions. I think I'll leave the challenge as it is now \$\endgroup\$ – Luis Mendo Oct 4 '15 at 15:16

64 Answers 64


Scala, 79, 66 bytes

Inspired by the Haskell version using foldLeft

def f(s:String)=s.foldLeft("")((a,c)=>if(a.contains(c))a else a+c)

Previous version using zipWithIndex and collect

def f(s:String)=s.zipWithIndex.collect{case(c,i)if s.indexOf(c)==i=>c}.mkString

Gema, 18 characters


Sample run:

bash-4.3$ gema '?=${?;$0}@set{$0;}' <<< 'hello world'
helo wrd

Ceylon, 98 bytes (stdio) / 68 bytes (function)

Here is a version without using Set or similar stuff, as a function (68 bytes):

String i(String s)=>String{for(x->c in s.indexed)if(!c in s[0:x])c};

The same with stdio (reading just one line) (98 bytes):

void q(){value s=process.readLine()else"";print(String{for(x->c in s.indexed)if(!c in s[0:x])c});}

The first one ungolfed (117 bytes):

String i(String s) => String{
        for (x->c in s.indexed)
            if (!c in s[0:x])

This uses the feature to build a string from an iterable of characters, but this time the iterable is build from a comprehension, which is passed to the string-constructor using the named-argument-list syntax. (This could also have been written as String({...});, using a positional argument list and an iterable-constructor, but that would have been two bytes more).

The comprehension consists of a for-clause (which iterates over an indexed version of the input string, i.e. x is the index corresponding to the character c) and an if-clause (which filters the character by checking if it appears in the substring up to the index).

We see here two different uses of the keyword in – once as part of the syntax of the for clause of comprehensions, and once as the in operator, which maps to s[0:x].contains(c).

The "thin arrow" in x->c is the syntax for an Entry made of x and c (as key and value). As an expression one can build an entry this way from its constituents, but here it is a part of the comprehension syntax (and also the syntax of the for-loop), and deconstructs the entry which is returned by the iterator of the iterable s.indexed.

The "fat arrow" => is a shorthand for defining a function whose body consists of just one expression (which is evaluated and returned) – that saves us the return and a pair of braces.

The variant which uses stdio:

void q() {
    value s = process.readLine() else "";
    print(String { for (x->c in s.indexed)
                if (!c in s[0:x])
                    c });

Unfortunately we need a variable here to store the string, because we need to access it twice (in the loop and in the filter).

Instead of using an Iterable comprehension, we can also use the stream-manipulating method filter together with the spread attribute operator *. and a lambda expression (e)=>!e.item in s[0:e.key] inbetween:

String j(String s)=>String(s.indexed.filter((e)=>!e.item in s[0:e.key])*.item);

This is even longer with 79 bytes.


Python, 62 bytes

lambda s:''.join([c for i,c in enumerate(s)if c not in s[:i]])
  • \$\begingroup\$ It's scored by size in bytes, I'll just edit it so its right... Also, you can move the space between the : ''.join so it's like :''.join \$\endgroup\$ – Blue Oct 6 '15 at 16:27
  • \$\begingroup\$ I don't think you need the outer square brackets. \$\endgroup\$ – HyperNeutrino Mar 23 '17 at 12:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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