41
\$\begingroup\$

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

    3.1415926535897932384626433832795
    

    Output string

    3.14592687
    
\$\endgroup\$
  • 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

2
\$\begingroup\$

C, 47 bytes

a[];main(c){for(;read(0,&c,1);write(!a[c]++));} 
\$\endgroup\$
2
\$\begingroup\$

Simplex v.0.7, 22 10 bytes

s^oR^l^Ryg
s          ~~ string input
 ^o        ~~ convert to tuple
   R       ~~ go right
    ^l     ~~ unicode tuple
      ^R   ~~ take intersection
        yg ~~ convert to string and output

sigh Minkolang is kicking Simplex's butt.

s^[oZ%_Q]n?[^_s^~M^=]]
s                      ~~ string input
 ^[     ]              ~~ postfixes each of the inner with a ^
   o                   ~~ convert to tuple
    Z                ] ~~ fold
     %                 ~~ tuple w/out current character + increment
      _                ~~ current character
       Q               ~~ membership
         n?[        ]  ~~ if current character not in tuple
            ^_s^~M^=   ~~ print that character 

\$\endgroup\$
  • 2
    \$\begingroup\$ What a coup for Simplex! \$\endgroup\$ – El'endia Starman Oct 28 '15 at 2:51
2
\$\begingroup\$

Octave, 25 bytes

@(s)s(sum(triu(s'==s))<2)
\$\endgroup\$
2
\$\begingroup\$

Javascript (ES6), 47 bytes

a=>[...a].filter((b,c)=>a.indexOf(b)==c).join``

Test it here

Some code is added to have a better input and to write to the console the result.

d=document,g=d.getElementById.bind(d);g("s").onclick=e=>console.log((a=>[...a].filter((b,c)=>a.indexOf(b)==c).join``)(g("t").value))
<input id="t"><button id="s">Convert</button>

\$\endgroup\$
2
\$\begingroup\$

Vim, 23 keystrokes

qq:s/\v(.).*\zs\1<cr>@qq@q

Explanation:

qq                           " Start recording into register 'q'
  :s/                        " Search and replace:
      \v                     " Enable 'magic', which just makes regexes a littl shorter
        (.)                  " Any symbol, captured in group one
           .*                " Anything
             \zs\1           " Start selection, group one
                             " Replace with nothing
                  <cr>       " Globally
                      @q     " Call macro q. Since we are still recording, this will not do anything the first time, and create a loop the next time
                        q    " Stop recording. 
                         @q  " Start the loop. This will run until there is no match.

Since V is backwards compatible, you can Try it online!

\$\endgroup\$
2
\$\begingroup\$

Ruby, 19 + 1 = 20 bytes

Uses the -p flag. Uses set operations like the GolfScript answer, which is totally not a built-in like uniq. (Performing set or on a list and an empty list purges the list of duplicates, just like calling and against a copy of itself.)

$_=($_.chars|[])*""
\$\endgroup\$
1
\$\begingroup\$

AutoIt, 107

Func _($0)
$1=''
For $2 In StringSplit($0,'',3)
$1&=StringInStr($1,$2,1)?'':$2
Next
Return $1
EndFunc

Call it like any function:

ConsoleWrite(_("Type unique chars!"))
\$\endgroup\$
1
\$\begingroup\$

Haskell, 50

f=concat.(tail>>=zipWith(\x y->[last x]\\y)).inits
\$\endgroup\$
  • 3
    \$\begingroup\$ inits is in Data.List, so you need an import, which is usually added to the byte count. \$\endgroup\$ – nimi Oct 4 '15 at 20:46
1
\$\begingroup\$

Java, 79 bytes

It's java, and it may be a little bit shorter than some of the more wordy esoteric languages.

But still, java.

s->{String r="";for(char c:s.toCharArray())r+=(r.indexOf(c)>-1)?"":c;return r;}

Explanation:

s->{ //Lambda expression opening, note that java can infer the type of s

    String r=""; //Initializes String r

    for(char c:s.toCharArray()) //Iterates through the string

        r+=(r.indexOf(c)>-1)?"":c; //indexOf(c) returns -1 if there are no occurrences

    return r;

}
\$\endgroup\$
  • \$\begingroup\$ I know it's been about 2.5 years, but you can golf it to s->{String r="";for(String c:s.split(""))r+=r.indexOf(c)<0?c:"";return r;}, or even six bytes shorter when using Java 10 instead of 8, so both String can be var. And I'm not 100% sure it's allowed, but I think you can just input it as a String-array instead so .split("") can be removed. In total: s->{var r="";for(var c:s)r+=r.indexOf(c)<0?c:"";return r;} Try it online 58 bytes. (Or alternatively: s->{var r="";for(var c:s)r=r.indexOf(c)<0?r+c:r;return r;} Also 58 bytes.) \$\endgroup\$ – Kevin Cruijssen Apr 6 '18 at 14:52
1
\$\begingroup\$

Delphi, 111 bytes

procedure u(var s:string);var i:word;begin for i:=length(s) downto 1 do if pos(s[i],s)<i then delete(s,i,1)end;

Using the procedure to alter the passed in string - saves a few bytes in comparison to declaring the function. Moving backwards through the string, delete the current character if it is not the first location of that character

\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6) 46

f=s=>[...s].map(c=>s[c]?'':s[c]=c,s=[]).join``

Unexpectedly, this time the flag array is one byte shorter than the indexOf approach.

\$\endgroup\$
1
\$\begingroup\$

SED, 61 bytes

s/^/\a/
:
s/\a\(\(.\).*\)\2/\a\1/
t
s/\a\(.\)/\1\a/
t
s/\a//
\$\endgroup\$
  • 1
    \$\begingroup\$ 2 characters shorter: s/\a\(.\)\(.*\)\1/\a\1\2/s/\a\(\(.\).*\)\2/\a\1/. If you have GNU sed you can remove the parenthesis escaping at the price of +1 for the -r switch. \$\endgroup\$ – manatwork Oct 6 '15 at 13:43
  • \$\begingroup\$ @manatwork: Nice, changed. (I could also shrink all \a sequences into a single unprintable BEL character, though I'm not sure it's really worth it) \$\endgroup\$ – Hasturkun Oct 6 '15 at 14:08
1
\$\begingroup\$

Perl 5.10+, 21 bytes

perl -pe '1while s/(.).*\K\1//'

20 bytes + 1 byte for -p. Note that Perl 5.10 or above is required for \K.

Takes input from stdin:

$ echo 'Type unique chars!' | perl -pe '1while s/(.).*\K\1//'
Type uniqchars!

$ echo \"I think it\'s dark and it looks like rain\", you said | perl -pe '1while s/(.).*\K\1//'
"I think'sdarloe,yu

$ echo 3.1415926535897932384626433832795 | perl -pe '1while s/(.).*\K\1//'
3.14592687

Online demo


Inspired by NinjaBearMonkey's Retina answer. Perl may not have a compact way to re-run a substitution until nothing changes, but it does have \K, which causes the regex engine to "keep" everything to its left. This allows you to drop a set of parentheses on the LHS and a capture variable on the RHS:

s/(.).*\K\1//   # 13 bytes

vs.

s/((.).*)\2/$1/ # 15 bytes
\$\endgroup\$
  • 1
    \$\begingroup\$ Save 1 byte using s/(.).*\K\1//&&redo \$\endgroup\$ – Ton Hospel Sep 28 '16 at 11:50
1
\$\begingroup\$

Python 3, 132 109 105 bytes

u=[]
def t(l):
 if l in u:return''
 else:
  u.append(l);return l
print(''.join([t(l)for l in input()]))

Ungolfed:

used_chars = []
def test(letter):
    if letter in used_chars:
        return '' # skip
    else:
        used_chars.append(letter)
        return letter
print(''.join([test(letter) for letter in input()]))
\$\endgroup\$
  • \$\begingroup\$ Shouldn't the r(l) in the last line be t(l)? \$\endgroup\$ – user4768 Oct 5 '15 at 9:16
  • \$\begingroup\$ Also, you can use print if you end the line with a comma: print ('%s') % (''.join([r(l)for l in i])), then import sys won't be necessary. \$\endgroup\$ – user4768 Oct 5 '15 at 9:19
  • \$\begingroup\$ Following Thomas Kwa's suggestion, one trailing \n is acceptable in stdout (in fact it's implicit in many functions used for displaying into stdout). I've made this explicit in the challenge rules. You may perhaps use that to reduce your code length \$\endgroup\$ – Luis Mendo Oct 5 '15 at 9:54
1
\$\begingroup\$

Perl 6, 32 bytes

The way you would normally write this would be:

$*IN.comb.unique.print # it would have been 22

Which would have had the benefit of being obviously correct.


Instead I have to write something like the following

print $*IN.comb.grep:{!.{$^a}++} # 32
\$\endgroup\$
1
\$\begingroup\$

Minkolang 0.10, 13 bytes

This language was made after this challenge but not for this challenge.

Much thanks to Sp3000 for pointing me the way to this much shorter solution.

od?.dd0q?Od0p

Try it here.

Explanation

od               Read character from input and duplicate it (for the conditional)
  ?.             Stop if 0 (i.e., input is empty)
    dd           Duplicate twice (for q and for possible output)
      0q         Gets value stored in (character,0) in the codebox (0 if empty)
        ?O       Outputs character if it's unique (i.e. the previous value was 0)
          d0p    Puts the value of the character at (value,0) in the codebox
\$\endgroup\$
1
\$\begingroup\$

AppleScript, 143 142 Bytes

set x to(display dialog""default answer"")'s text returned's characters
set o to""
repeat with i in x
if not i is in o then set o to o&i
end
o

Not a language for golfing, but it's very readable.

\$\endgroup\$
1
\$\begingroup\$

R, 52 bytes

cat(union(a<-strsplit(readline(),"")[[1]],a),sep="")

Test examples:

Type uniqchars!
"I think'sdarloe,yu
3.14592687
\$\endgroup\$
1
\$\begingroup\$

RProgN, 85 Bytes, Non Competing

S i 'a' = s 'n' = a L while a pop 'b' = n b hasvalue ! if n b push end a L end n i ++

Explanation

S i                     # Take the implicit string input, convert it to a stack such that the first letter is at the bottom, invert the stack such that the first letter is at the top.
'a' =                   # Associate it with 'a'
s 'n' =                 # Create a new stack, associate it with 'n'
a L                     # Push the size of a
while                   # While the top of the stack contains a truthy value
    a pop 'b' =         # Pop the top of a, associate it with 'b'
    n b hasvalue !      # Push if the stack 'n' does not contain b
    if                  # If the top of the stack is truthy
        n b push        # Push b to the stack n
    end                 #
    a L                 # Push the length of a
end                     # loop
n i ++                  # Push the n, inverts it, sums it, which acts to concatenate it, implicitly print the result.

Non-Competing as the 'Not' and 'HasValue' functions were both not implemented prior to this challenge.

\$\endgroup\$
1
\$\begingroup\$

REXX, 79 bytes

a=arg(1)
o=
do while a>''
  parse var a b+1 a
  if pos(b,o)=0 then o=o||b
  end
say o
\$\endgroup\$
1
\$\begingroup\$

Python, 61 59 bytes

lambda s:''.join(i for c,i in enumerate(s)if s.index(i)==c)

str.index always returns the first occurrence, so only output the character if the current occurrence is the first occurrence.

Edit: The square brackets were unnecessary.

\$\endgroup\$
1
\$\begingroup\$

PHP, 47 Bytes

for(;a&$c=$argn[$i++];)$r[$c]=$c;echo join($r);

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Python 2, 79

def S(s):
 s=s[::-1]
 for c in s:s=s.replace(c,'',s.count(c)-1)
 return s[::-1]

It reverses the input string, cycles through it, replaces any extra characters with null ones and returns the reverse of that. The reverse is so the last characters are removed, not the first.

>>> S('''"I think it's dark and it looks like rain", you said''')
'"I think\'sdarloe,yu'
>>> S("3.1415926535897932384626433832795")
'3.14592687'
>>> S("Type unique chars!")
'Type uniqchars!'
\$\endgroup\$
0
\$\begingroup\$

Haskell, 33 bytes

foldl(\r c->r++[c|notElem c r])[]

Uses foldl to iterate through the string appending characters that are not in the current result, starting with the empty string (list).

\$\endgroup\$
0
\$\begingroup\$

Scala, 118 bytes

def f(a:String):String={a=>a.zipWithIndex.groupBy(_._1.toLower).map(_._2.head).toList.sortBy(_._2).map(_._1).mkString}
\$\endgroup\$
0
\$\begingroup\$

MUMPS, 54 bytes

f(s) f i=1:1:$L(s) s c=$E(s,i) s:t'[c o=o_c,t=t_c
    q o

Not terribly exciting - it just keeps a running list of already-viewed characters and only appends to the output string if the current character isn't in that list.

\$\endgroup\$
0
\$\begingroup\$

Powershell, 30

$args-replace'(.)(?<=\1.+)',''

I feel there's likely to be a better regex than this, and I can't work out what it is

\$\endgroup\$
0
\$\begingroup\$

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

This version is using stdio and a HashSet, 98 bytes:

import ceylon.collection{H=HashSet}shared void u(){print(String(H{*(process.readLine()else"")}));}

This is just a function String → String (also using a HashSet), 69 bytes:

import ceylon.collection{H=HashSet}String n(String i)=>String(H{*i});

Ungolfed version:

import ceylon.collection {
    HashSet
}
void uniq() {
    value input = process.readLine() else "";
    value set = HashSet { elements = input; };
    print(String(set));
}

A Ceylon HashSet by default is linked (i.e. conserves the insertion order as iteration order). We use here the named-argument syntax to pass the elements argument to the HashSet constructor.

A string is also an iterable of characters, and as such can be passed to the elements parameter. A string can also be constructed from such a sequence, which is what we do in the last command.

The golfed version again: import ceylon.collection{H=HashSet}shared void u(){print(String(H{*(process.readLine()else"")}));}

Some used tricks:

  • Variable inlining
  • If we have to import HashSet anyways, give it a shorter name.
  • The named-argument syntax accepts also a "normal" argument list. Any arguments in that list will be, if they don't fit the other arguments, be wrapped in an Iterable and passed to an Iterable argument (if there is one). To spread our existing iterable (the input string) into such an argument list, we use the "spread operator *".

If we don't have to handle standard-input and output and just need a function, this is shorter:

import ceylon.collection{HashSet}
String n(String i) => String(HashSet{*i});

The explanations from above are still valid.

\$\endgroup\$
0
\$\begingroup\$

Rust, 318 Bytes

not really a competitor, but rust needs a bit more love. As always, comments and advice welcome.

use std::io;fn main(){let mut s=io::stdin();let mut b=String::new();s.read_line(&mut b).unwrap();let mut n: Vec<char>=b.chars().collect();for i in 0..n.len()-2{let mut j=i+1;let mut p = true;while j<n.len(){if j<n.len(){if n[i]==n[j]{n.remove(j);p=false;}}if p{j+=1;}p=true;}}for i in 0..n.len()-2{print!("{}",n[i]);}}

Try it online here (first compile, then execute, then click into the proper area to enter user input)

ungolfed:

use std::io;
fn main() {
let mut s = io::stdin();
let mut b=String::new();
s.read_line(&mut b).unwrap();
let mut chars: Vec<char> = b.chars().collect();
for i in 0..chars.len()-2 {
    let mut j=i+1;
    let mut inc = true;
    while j<chars.len() {
        if j<chars.len() 
        {
            if chars[i]==chars[j] {
                chars.remove(j);
                inc = false;
            }
        }
        if inc {
            j+=1;
        }
        inc = true;
    }
}
for i in 0..chars.len()-2 {
    print!("{}",chars[i]);
}
}
\$\endgroup\$
0
\$\begingroup\$

Python 2, 62 bytes

s=set();print filter(lambda i:not(i in s or s.add(i)),input())
\$\endgroup\$

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.