46
\$\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\$
16
  • 6
    \$\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
  • 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
  • 2
    \$\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
  • 1
    \$\begingroup\$ -1 Disallowing built-ins serves no purpose other than making interesting answers. This is code-golf, not popularity contests. \$\endgroup\$
    – MilkyWay90
    Apr 6 '19 at 2:26

74 Answers 74

17
\$\begingroup\$

GolfScript, 2 bytes

.&

or, alternatively:

.|

I posted this a while ago in the Tips for golfing in GolfScript thread. It works by duplicating the input string (which is put on the stack automatically by the GolfScript interpreter, and which behaves in most ways like an array of characters) and then taking the set intersection (&) or union (|) of it with itself. Applying a set operator to an array (or string) collapses any duplicates, but preserves the order of the elements.

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

CJam, 3 bytes

qL|

Setwise or of the input with an empty list. CJam set operations preserve element order.

Try it online

\$\endgroup\$
2
  • \$\begingroup\$ I'm assuming this is valid since sets are allowed, but I'm not sure... \$\endgroup\$
    – Sp3000
    Oct 4 '15 at 14:58
  • \$\begingroup\$ Very clever! I knew CJam would be one of the best, but I didn't expect just 3 bytes! \$\endgroup\$
    – Luis Mendo
    Oct 4 '15 at 14:59
20
\$\begingroup\$

C# 6, 18 + 67 = 85 bytes

Requires this using statement:

using System.Linq;

The actual method:

string U(string s)=>string.Concat(s.Where((x,i)=>s.IndexOf(x)==i));

This method saves some chars by defining the function as a lambda, which is supported in C# 6. This is how it would look in C# pre-6 (but ungolfed):

string Unique(string input)
{
    return string.Concat(input.Where((x, i) => input.IndexOf(x) == i));
}

How it works: I call the Where method on the string with a lambda with two arguments: x representing the current element, i representing the index of that element. IndexOf always returns the first index of the char passed to it, so if i is not equal to the first index of x, it's a duplicate char and mustn't be included.

\$\endgroup\$
5
  • 3
    \$\begingroup\$ I honestly wouldn't have expected C# to be this short. Excellent job! \$\endgroup\$
    – Alex A.
    Oct 4 '15 at 17:40
  • \$\begingroup\$ Uhm. I think you should submit a complete program (with static void Main etc.). \$\endgroup\$
    – Timwi
    Oct 5 '15 at 10:49
  • 3
    \$\begingroup\$ @Timwi This challenge states "Either functions or programs are allowed." \$\endgroup\$
    – hvd
    Oct 5 '15 at 14:22
  • \$\begingroup\$ C# allows for a shorter approach, also using LINQ. I've posted a competing answer. :) \$\endgroup\$
    – hvd
    Oct 5 '15 at 14:37
  • \$\begingroup\$ @hvd Nice one! +1 \$\endgroup\$
    – ProgramFOX
    Oct 5 '15 at 15:19
15
\$\begingroup\$

Retina, 14 bytes

+`((.).*)\2
$1

Each line should go in its own separate file, or you can use the -s flag to read from one file.

To explain it, we'll use this longer but simpler version:

+`(.)(.*)\1
$1$2

The first line is the regex to match with (+` is the configuration string that keeps running until all replacements have been made). The regex looks for a character (we'll call it C), followed by zero or more arbitrary characters, followed by C. The parentheses denote capturing groups, so we replace the match with C ($1) and the characters in between ($2), removing the duplicate of C.

For example, if the input string was unique, the first run would match uniqu, with u and niq as $1 and $2, respectively. It would then replace the matched substring in the original input with uniq, giving uniqe.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ I was looking for a regex to do this; I didn't realize it was so short! +1 \$\endgroup\$ Oct 4 '15 at 22:54
14
\$\begingroup\$

Perl 5 + -p, 19 bytes

Saved 1 byte thanks to @kos and 1 byte thanks to @Xcali!

s/./$&x!$h{$&}++/eg

Try it online!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ You could save 1 byte negating $h{$&} and using a logic AND instead of a ternary operator: s/./!$h{$&}++&&$&/eg \$\endgroup\$
    – kos
    Oct 5 '15 at 12:55
  • \$\begingroup\$ @kos if you'd asked me, I'd have told you that I 100% tried this and ended up with 1s in the output, but it doesn't! Thank you, updating! \$\endgroup\$ Oct 5 '15 at 15:51
  • 1
    \$\begingroup\$ Upvoted already :) I think you tried s/./$h{$&}++||$&/eg (I fell for that as well at first). Shame because that would have been another saved byte. \$\endgroup\$
    – kos
    Oct 5 '15 at 16:03
  • 1
    \$\begingroup\$ Got it down one more byte: Try it online! \$\endgroup\$
    – Xcali
    Jan 15 at 7:07
  • \$\begingroup\$ @Xcali Nice one! Thanks! \$\endgroup\$ Jan 15 at 10:34
12
\$\begingroup\$

JavaScript ES7, 37 33 25 bytes

Pretty simple approach using ES6 Set and ES7 Array comprehensions spread operator:

s=>[...new Set(s)].join``

22 bytes less than the indexOf approach. Worked on a handful of test cases.

\$\endgroup\$
8
  • \$\begingroup\$ The spaces around for's expression are not necessary and you could make it anonymous function as some other solutions did: s=>[for(c of Set(s))c].join``. (Pale update: not 100% sure, but the new keyword seems also unnecessary.) \$\endgroup\$
    – manatwork
    Oct 5 '15 at 10:36
  • \$\begingroup\$ Wasn't sure of the rules with anon functions, and good catch on the space. \$\endgroup\$
    – azz
    Oct 5 '15 at 10:37
  • \$\begingroup\$ Transpiled code without new resulted in Uncaught TypeError: Constructor Set requires 'new' in Google Chrome. \$\endgroup\$
    – azz
    Oct 5 '15 at 10:43
  • \$\begingroup\$ Please excuse my ignorance but at what point does this filter unique values? It looks like it just converts a string to a set to an array then joins the values resulting in the original string again. \$\endgroup\$ Oct 5 '15 at 14:17
  • \$\begingroup\$ @PatrickRoberts it's the conversion to a set. A set by definition has no dupluicates \$\endgroup\$
    – edc65
    Oct 5 '15 at 14:32
11
\$\begingroup\$

Macaroni 0.0.2, 233 bytes

set i read set f "" print map index i k v return label k set x _ set _ slice " " length index f e 1 1 set f concat f wrap x return label e set _ slice " " add _ multiply -1 x 1 1 return label v set _ unwrap slice i _ add 1 _ 1 return
  • create "anti-golfing" language: check
  • golf it anyway: check

This is a full program, which inputs from STDIN and outputs on STDOUT.

Wrapped version, for aesthetic value:

set i read set f "" print map index i k v return label k set x _ set _ slice "
" length index f e 1 1 set f concat f wrap x return label e set _ slice " " add
_ multiply -1 x 1 1 return label v set _ unwrap slice i _ add 1 _ 1 return

And a heavily "commented" and ungolfed version (there are no comments in Macaroni, so I just use bare string literals):

set input read                  "read line from STDIN, store in 'input' var"
set found ""                    "we need this for 'keep' below"
print map index input keep val  "find indeces to 'keep', map to values, print"
return

label keep
    "we're trying to determine which indeces in the string to keep. the special
     '_' variable is the current element in question, and it's also the value
     to be 'returned' (if the '_' variable is '0' or empty array after this
     label returns, the index of the element is *not* included in the output
     array; otherwise, it is"
    set x _ set _ slice
        " "
        length index found exists
        1
        1
    "now we're using 'index' again to determine whether our '_' value exists in
     the 'found' array, which is the list of letters already found. then we
     have to apply a boolean NOT, because we only want to keep values that do
     NOT exist in the 'found' array. we can 'invert' a boolean stored as an
     integer number 'b' (hence, 'length') with 'slice(' ', b, 1, 1)'--this is
     equivalent to ' '[0:1], i.e. a single-character string which is truthy, if
     'b' was falsy; otherwise, it results in an empty string if 'b' was truthy,
     which is falsy"
    set found concat found wrap x  "add the letter to the 'found' array"
return

label exists
    set _ slice
        " "
        add _ multiply -1 x
        1
        1
    "commentary on how this works: since 0 is falsy and every other number is
     truthy, we can simply subtract two values to determine whether they are
     *un*equal. then we apply a boolean NOT with the method described above"
return

label val
    set _ unwrap slice input _ add 1 _ 1  "basically 'input[_]'"
return

(This is the first real Macaroni program (that actually does something)! \o/)

\$\endgroup\$
1
  • 5
    \$\begingroup\$ • give the language a funny and appropriate name: check \$\endgroup\$
    – Luis Mendo
    Oct 4 '15 at 15:32
9
\$\begingroup\$

C# 6 - 18+46=64

using System.Linq;

and then

string f(string s)=>string.Concat(s.Union(s));

The Enumerable.Union extension method specifies that elements are returned in the original order:

When the object returned by this method is enumerated, Union enumerates first and second in that order and yields each element that has not already been yielded.

Set operations that aren't specifically intended to find unique values appear to be allowed judging by the other answers.

\$\endgroup\$
6
  • \$\begingroup\$ Nice one, I was thinking of string u(string s)=>String.Join("",s.Distinct()); but that's a little bit longer. \$\endgroup\$
    – germi
    Oct 7 '15 at 12:41
  • \$\begingroup\$ @germi Thanks. There has been an answer using Distinct() already, but it's deleted because Distinct() is disallowed in this challenge, as it's a method specifically intended to find unique values. \$\endgroup\$
    – hvd
    Oct 7 '15 at 12:43
  • \$\begingroup\$ Ah right... overlooked that bit ;) \$\endgroup\$
    – germi
    Oct 7 '15 at 12:47
  • \$\begingroup\$ Is s => string.Concat(s.Union(s)) valid? That would be the delegate passed to a Func<string, string> as an argument. \$\endgroup\$ Sep 28 '16 at 3:17
  • \$\begingroup\$ @TylerStandishMan If that's valid, I would expect more people to make use of it, and I haven't seen it before, so I don't think it is. But maybe it should be valid -- this seems like something worth checking on Meta if you're interested. \$\endgroup\$
    – hvd
    Sep 28 '16 at 5:02
8
\$\begingroup\$

><>, 16 bytes

i:0(?;:::1g?!o1p

><> doesn't have strings, so we make use of the codebox. Due to the toroidal nature of ><>, the following runs in a loop:

i         Read a char
:0(?;     Halt if EOF
:::       Push three copies of the char
1g        Get the value at (char, 1), which is 0 by default
?!o       Print the char if the value was nonzero
1p        Set the value at (char, 1) to char

Note that this uses the fact that the input only contains printable ASCII, as this would not work if ASCII 0 was present.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ .......this is brilliant. I wish I had thought of this. I'll include a Befunge version of this in my answer, but not as the primary. EDIT: On second thought, this wouldn't work because Befunge doesn't have an infinite code space. Dangit! \$\endgroup\$ Oct 5 '15 at 5:52
  • \$\begingroup\$ @El'endiaStarman I think the Beam answer also does the same thing, so unfortunately I can't say I was first :P \$\endgroup\$
    – Sp3000
    Oct 5 '15 at 5:53
  • \$\begingroup\$ Ahh, yeah, I think you're right. Your explanation is clearer though. \$\endgroup\$ Oct 5 '15 at 6:03
8
\$\begingroup\$

Python 2, 42 bytes

Uses a couple anonymous functions and reduce.

lambda s:reduce(lambda x,y:x+y[y in x:],s)

Try it online

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

Beam, 23 18 bytes

v<H
vs)
rS
g@S
>u^

enter image description here

Try it online!

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

JavaScript ES6, 47 bytes

f=s=>s.replace(/./g,(e,i)=>s.indexOf(e)<i?'':e)

The test below works on all browsers.

f=function(s){
  return s.replace(/./g,function(e,i){
    return s.indexOf(e)<i?'':e
  })
}

run=function(){document.getElementById('output').innerHTML=f(document.getElementById('input').value)};document.getElementById('run').onclick=run;run()
<input type="text" id="input" value="Type unique chars!" /><button id="run">Run</button><br />
<pre id="output"></pre>

\$\endgroup\$
2
  • \$\begingroup\$ What does the <i?'':e part do? \$\endgroup\$
    – DanTheMan
    Oct 7 '15 at 1:50
  • 1
    \$\begingroup\$ It's a ternary operator. If the first instance of a character e is before the current index i, it returns an empty string, thus getting rid of the character. If that is the first instance, it simply returns e and no changes are made. \$\endgroup\$ Oct 7 '15 at 3:03
7
\$\begingroup\$

MATLAB, 23

 @(n)union(n,n,'stable')

Does the "set union" of the input string with itself, using the 'stable' method which does not sort, and then prints.

This works because union returns only non-duplicate values after the merge. So essentially if you union the string with itself, it first produces a string like Type unique chars!Type unique chars!, and then removes all duplicates without sorting.

No need for unique :)

\$\endgroup\$
7
  • \$\begingroup\$ unique not allowed, sorry! It's in the challange definition \$\endgroup\$
    – Luis Mendo
    Oct 4 '15 at 15:28
  • \$\begingroup\$ Missed that, never mind. \$\endgroup\$ Oct 4 '15 at 15:31
  • \$\begingroup\$ Following Sp3000's answer, may I suggest setdiff with the 'stable' option? \$\endgroup\$
    – Luis Mendo
    Oct 4 '15 at 15:39
  • 1
    \$\begingroup\$ Nice! And yes, you can remove disp because then you have a function that returns a string , which is allowed \$\endgroup\$
    – Luis Mendo
    Oct 4 '15 at 16:20
  • 1
    \$\begingroup\$ You can also use intersect with 'stable' to achieve the same effect too. I was going to write that, but given this answer, it's no longer original lol. \$\endgroup\$
    – rayryeng
    Oct 4 '15 at 17:24
7
\$\begingroup\$

Python 3, 44

r=''
for c in input():r+=c[c in r:]
print(r)

Builds the output string r character by character, including the character c from the input only if we haven't seen it already.

Python 2 would be 47, losing 4 chars with raw_input and saving 1 on not needing parers for print.

\$\endgroup\$
1
  • \$\begingroup\$ The consensus now seems to be that you can use input in Python 2, so you can make yours a byte shorter. \$\endgroup\$
    – mbomb007
    Sep 28 '16 at 13:24
6
\$\begingroup\$

Element, 22 19 18 bytes

_'{"(3:~'![2:`];'}

Example input/output: hello world -> helo wrd

This works by simply processing the string one character at a time and keeping track which ones it has seen before.

_'{"(3:~'![2:`];'}
_                        input line
 '                       use as conditional
  {              }       WHILE loop
   "                     retrieve string back from control (c-) stack
    (                    split to get the first character of (remaining) string
     3:                  a total of three copies of that character
       ~                 retrieve character's hash value
        '                put on c-stack
         !               negate, gives true if undef/empty string
          [   ]          FOR loop
           2:`           duplicate and output
               ;         store character into itself
                '        put remaining string on c-stack as looping condition
\$\endgroup\$
6
\$\begingroup\$

APL, 3

∊∪/

This applies union (∪) between each element of the vector, obtaining an iteration that has the effect of removing duplicates.

Test it on tryapl.org

Old One:

~⍨\

This uses ~ (with reversed arguments, using ⍨) applied between each element of the argument. The result is that for each element, if it's already in the list, it gets erased.

\$\endgroup\$
2
  • \$\begingroup\$ Nitpicking: "And input/output should be strings" says Luis. "Unione reduce" returns a nested array, not a string. O:-) \$\endgroup\$
    – lstefano
    Jun 28 '16 at 11:28
  • \$\begingroup\$ You're right, adding a ∊ at the beginning to correct. \$\endgroup\$ Jun 28 '16 at 14:42
5
\$\begingroup\$

Pyth, 7 bytes

soxzN{z

Pseudocode:

z = input

sum of order-by index in z of N over set of z.

\$\endgroup\$
4
\$\begingroup\$

TI-BASIC, 49 bytes

Input Str1
"sub(Str1,X,1→Y₁
Y₁(1
For(X,2,length(Str1
If not(inString(Ans,Y₁
Ans+Y₁
End
Ans

The equation variables are rarely useful since they take 5 bytes to store to, but Y₁ comes in handy here as the Xth character of the string, saving 3 bytes. Since we can't add to empty strings in TI-BASIC, we start the string off with the first character of Str1, then loop through the rest of the string, adding all characters not already encountered.

prgmQ
?Why no empty st
rings? Because T
I...
Why noemptysrig?Bcau.
\$\endgroup\$
4
\$\begingroup\$

Perl, 54 27 bytes

map{$h{$_}||=print}<>=~/./g
123456789012345678901234567

Test:

$ echo Type unique chars! | perl -e 'map{$h{$_}||=print}<>=~/./g'
Type uniqchars!
$
\$\endgroup\$
6
  • 1
    \$\begingroup\$ print exists($h{$_})?"":$_$h{$_}||print \$\endgroup\$
    – manatwork
    Oct 4 '15 at 16:25
  • \$\begingroup\$ Has SO inserted a unicode → char in there rendering it broken? \$\endgroup\$
    – steve
    Oct 4 '15 at 16:29
  • 1
    \$\begingroup\$ using a statement modifier would save you some bytes, along with @manatwork's suggestion $h{$_}||=print and using <>=~/./g should help save a few more as well! \$\endgroup\$ Oct 4 '15 at 16:30
  • 1
    \$\begingroup\$ No, I inserted it, with the meaning of “change to”. \$\endgroup\$
    – manatwork
    Oct 4 '15 at 16:30
  • 1
    \$\begingroup\$ Changing to map would also improve the saving: map{$h{$_}||=print}<>=~/./g \$\endgroup\$
    – manatwork
    Oct 4 '15 at 16:32
4
\$\begingroup\$

PHP, 72 Bytes 84 Bytes

<?foreach(str_split($argv[1])as$c)$a[$c]=0;echo join('',array_keys($a));

Uses the characters as keys for an associative array, then prints the keys. Order of array elements is always the order of insertion.

Thanks Ismael Miguel for the str_split suggestion.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ <?foreach(str_split($argv[1])as$c)$a[$c]=0;echo join('',array_keys($a)); Shorter and does the same. \$\endgroup\$ Oct 4 '15 at 20:27
  • \$\begingroup\$ Found a shorter loop: while($c=$argv[1][$i++*1]). This replaces the whole foreach. Everything else is the same \$\endgroup\$ Oct 4 '15 at 20:43
  • \$\begingroup\$ I tried something similar first but refrained from it because it would stop on a character that coerces to "false", i.e. "0". Try "abc0def" as input. \$\endgroup\$ Oct 4 '15 at 20:47
  • \$\begingroup\$ You're right about it. Surelly there's a workaround for it that doesn't cost more than 2 bytes. \$\endgroup\$ Oct 4 '15 at 20:48
4
\$\begingroup\$

Julia, 45 42 bytes

s->(N="";[i∈N?N:N=join([N,i])for i=s];N)

Old version:

s->(N={};for i=s i∈N||(N=[N,i])end;join(N))

Code builds the new string by appending new characters onto it, then joins them together to a proper string at the end. New version saves some characters by iterating via array comprehension. Also saves a byte by using ?: rather than || (as it removes the need for brackets around the assignment).

Alternate solution, 45 bytes, using recursion and regex:

f=s->s!=(s=replace(s,r"(.).*\K\1",""))?f(s):s

Julia, 17 bytes

(Alternate version)

s->join(union(s))

This uses union as basically a substitute for unique - I don't consider this the "real" answer, as I interpret "don't use unique" to mean "don't use a single built-in function that has the effect of returning the unique elements".

\$\endgroup\$
1
  • \$\begingroup\$ I had a similar idea but it wasn't as concise. Nice work! \$\endgroup\$
    – Alex A.
    Oct 4 '15 at 17:38
4
\$\begingroup\$

Java, 78 bytes

String f(char[]s){String t="";for(char c:s)t+=t.contains(c+"")?"":c;return t;}

A simple loop while checking the output for characters already present. Accepts input as a char[].

\$\endgroup\$
4
\$\begingroup\$

Haskell, 29 bytes

Nestable, no-variable-name one-liner:

foldr(\x->(x:).filter(x/=))[]

Same count, saved into a function named f as a top-level declaration:

f(x:t)=x:f[y|y<-t,x/=y];f_=[]

Note that there is a slightly-cheating optimization which I haven't made in the spirit of niceness: it is technically still allowed by the rules of this challenge to use a different input and output encoding for a string. By representing any string by its partially-applied Church encoding \f -> foldr f [] string :: (a -> [b] -> [b]) -> [b] (with the other side of the bijection provided by the function ($ (:))) this gets golfed down to ($ \x->(x:).filter(x/=)), only 24 characters.

I avoided posting the 24-character response as my official one because the above solution could be tried on the above interpreter as foldr(\x->(x:).filter(x/=))[]"Type unique chars!"whereas the golfed solution would be written instead:

($ \x->(x:).filter(x/=))$ foldr (\x fn f->f x (fn f)) (const []) "Type unique chars!"

as a shorthand for the literal declaration which would be the more-insane:

($ \x->(x:).filter(x/=))$ \f->f 'T'.($f)$ \f->f 'y'.($f)$ \f->f 'p'.($f)$ \f->f 'e'.($f)$ \f->f ' '.($f)$ \f->f 'u'.($f)$ \f->f 'n'.($f)$ \f->f 'i'.($f)$ \f->f 'q'.($f)$ \f->f 'u'.($f)$ \f->f 'e'.($f)$ \f->f ' '.($f)$ \f->f 'c'.($f)$ \f->f 'h'.($f)$ \f->f 'a'.($f)$ \f->f 'r'.($f)$ \f->f 's'.($f)$ \f->f '!'.($f)$ const[]

But it's a perfectly valid version of the data structure represented as pure functions. (Of course, you can use \f -> foldr f [] "Type unique chars!" too, but that is presumably illegitimate since it uses lists to actually store the data, so its foldr part should then presumably be composed into the "answer" function, leading to more than 24 characters.)

\$\endgroup\$
4
\$\begingroup\$

C - 58

Thanks to @hvd and @AShelly for saving a bunch of characters. There were multiple ways suggested of making it much shorter than the original:

// @hvd     - always copy to q but only increment q if not found
g(char*s,char*r){char*q=r;for(;*q=*s;q+=q==strchr(r,*s++));}

// @AShelly - keep a histogram of the usage of each character
h(char*s){int a[128]={0};for(;*s;s++)a[*s]++||putchar(*s);}

// @hvd     - modify in place
i(char*s){char*q=s,*p=s;for(;*q=*p;q+=q==strchr(s,*p++));}

// original version - requires -std=c99
void f(char*s,char*r){for(char*q=r;*s;s++)if(!strchr(r,*s))*q++=*s;}

As you can see modifying in place seems to be the shortest (so far!) The test program compiles without warnings using gcc test.c

#include <stdlib.h> // calloc
#include <string.h> // strchr
#include <stdio.h>  // puts, putchar

// 000000111111111122222222223333333333444444444455555555556666666666
// 456789012345678901234567890123456789012345678901234567890123456789

// @hvd     - always copy to q but only increment q if not found
g(char*s,char*r){char*q=r;for(;*q=*s;q+=q==strchr(r,*s++));}

// @AShelly - keep a histogram of the usage of each character
h(char*s){int a[128]={0};for(;*s;s++)a[*s]++||putchar(*s);}

// @hvd     - modify in place
i(char*s){char*q=s,*p=s;for(;*q=*p;q+=q==strchr(s,*p++));}

/* original version - commented out because it requires -std=c99
void f(char*s,char*r){for(char*q=r;*s;s++)if(!strchr(r,*s))*q++=*s;}
*/

// The test program:
int main(int argc,char*argv[]){
  char *r=calloc(strlen(argv[1]),1); // make a variable to store the result
  g(argv[1],r);                      // call the function
  puts(r);                           // print the result

  h(argv[1]);                        // call the function which prints result
  puts("");                          // print a newline

  i(argv[1]);                        // call the function (modifies in place)
  puts(argv[1]);                     // print the result
}

Thanks for all the help. I appreciate all the advice given to shorten so much!

\$\endgroup\$
11
  • \$\begingroup\$ Well, since your code already isn't valid C, just accepted by lenient C compilers: you can declare r as int (and omit the int) to save some bytes: f(s,r)char*s;{...}. But it limits your code to platforms where char* is the same size as int, and of course where compilers are as lenient as yours and mine. \$\endgroup\$
    – hvd
    Oct 6 '15 at 9:00
  • \$\begingroup\$ @hvd That's evil! I was willing to default the return value because I don't use it. But that's a bit more dodgy than I would like to be. I think I would prefer making it compliant rather than going that far! Thanks for bringing back to the light side. \$\endgroup\$ Oct 6 '15 at 9:07
  • \$\begingroup\$ You can save one char by replacing if(x)y with x?y:0 \$\endgroup\$
    – ugoren
    Oct 6 '15 at 12:17
  • \$\begingroup\$ Here's a 60 char function that writes to stdout instead of an array parameter: f(char*s){int a[128]={0};for(;*s;s++)a[*s]++?0:putchar(*s);} \$\endgroup\$
    – AShelly
    Oct 6 '15 at 17:29
  • \$\begingroup\$ You can unconditionally copy into *q, and only increment q if the character appeared earlier, allowing stuffing a bit more together: void f(char*s,char*r){for(char*q=r;*q=*s;strchr(r,*s++)<q||q++);} (Note that strchr(r,*s++)<q is always well-defined, there's no UB there, because strchr cannot return NULL in this version.) Except for the return type, it's even shorter than @AShelly's version. \$\endgroup\$
    – hvd
    Oct 6 '15 at 17:30
3
\$\begingroup\$

Ruby, 30 24 characters

(23 characters code + 1 character command line option.)

gsub(/./){$`[$&]?"":$&}

Sample run:

bash-4.3$ ruby -pe 'gsub(/./){$`[$&]?"":$&}' <<< 'hello world'
helo wrd
\$\endgroup\$
3
\$\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\$
1
  • 1
    \$\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\$ Apr 6 '18 at 14:52
3
\$\begingroup\$

Befunge-93, 124 bytes

v
<v1p02-1
0_v#`g00: <0_@#+1::~p
 1>:1+10p2+0g-!#v_v
g `#v_10g0^       >:10g00
 ^0g 00$        <
 ^  >:,00g1+:00p1+:1+01-\0p

Test it in this online interpreter.


This was more difficult than I expected. I'll post a fuller explanation tomorrow if anyone wants me to, but here's an overview of what my code does.

  • Unique characters seen so far are stored on the first row, starting from 2,0 and extending to the right. This is checked against to see if the current character is a duplicate.
  • The number of unique characters seen so far is stored in 0,0 and the check-for-duplicate loop counter is stored in 1,0.
  • When a unique character is seen, it is stored on the first row, printed out, and the counter in 0,0 is incremented.
  • To avoid problems with reading in the spaces present (ASCII 32), I put the character corresponding to -1 (really, 65536) in the next slot for the next unique character.
\$\endgroup\$
3
\$\begingroup\$

C, 96 bytes

#include<stdio.h> 
int c,a[128];main(){while((c=getchar())-'\n')if(!a[c])a[c]=1,putchar(c);}

This uses an array of integers, indexed by ASCII character number. The characters are only printed if that place in the array is set to FALSE. After each new character is found that place in the array is set to TRUE. This takes a line of text from standard input, terminated by a newline. It ignores non-ASCII characters.


Ungolfed:

#include<stdio.h>
#include<stdbool.h>

int main(void)
{
  int i, c;
  int ascii[128];
  for (i = 0; i < 128; ++i) {
    ascii[i] = false;
  }
  while ((c = getchar()) != '\n') {
    if (ascii[c] == false) {
      ascii[c] = true;
      putchar(c);
    }
  }
  puts("\n");
  return(0);
}
\$\endgroup\$
3
\$\begingroup\$

PHP, 56 54

// 56 bytes
<?=join('',array_flip(array_flip(str_split($argv[1]))));

// 54 bytes
<?=join(!$a='array_flip',$a($a(str_split($argv[1]))));

Edging out @fschmengler's answer using array_flip twice - second version uses variable method and relies on casting the string to true, negating it to false, then casting it back to the empty string in the first argument to save a couple of bytes in the second. Cheap!

\$\endgroup\$
3
\$\begingroup\$

C, 47 bytes

a[];main(c){for(;read(0,&c,1);write(!a[c]++));} 
\$\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.