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

13
\$\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\$
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\$
  • \$\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
19
\$\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\$
  • 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
14
\$\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\$
  • 3
    \$\begingroup\$ I was looking for a regex to do this; I didn't realize it was so short! +1 \$\endgroup\$ – ETHproductions Oct 4 '15 at 22:54
13
\$\begingroup\$

Perl, 21 (20 bytes + -p)

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

Usage:

perl -pe 's/./!$h{$&}++&&$&/eg' <<< 'Type unique chars!'
Type uniqchars!
\$\endgroup\$
  • 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\$ – Dom Hastings 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
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\$
  • 5
    \$\begingroup\$ • give the language a funny and appropriate name: check \$\endgroup\$ – Luis Mendo Oct 4 '15 at 15:32
11
\$\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\$
  • \$\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\$ – Patrick Roberts 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
8
\$\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\$
  • \$\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\$ – Tyler StandishMan 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
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\$
  • \$\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\$ – NinjaBearMonkey 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\$
  • \$\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\$ – Tom Carpenter 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\$

><>, 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\$
  • 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\$ – El'endia Starman 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\$ – El'endia Starman Oct 5 '15 at 6:03
7
\$\begingroup\$

Beam, 23 18 bytes

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

enter image description here

Try it online!

\$\endgroup\$
5
\$\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\$
5
\$\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\$
4
\$\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\$
  • \$\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
4
\$\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\$
  • \$\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\$ – Moris Zucca Jun 28 '16 at 14:42
3
\$\begingroup\$

Perl, 54 27 bytes

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

Test:

$ echo Type unique chars! | perl -e 'map{$h{$_}||=print}<>=~/./g'
Type uniqchars!
$
\$\endgroup\$
  • 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\$ – Dom Hastings 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
3
\$\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\$
  • 1
    \$\begingroup\$ <?foreach(str_split($argv[1])as$c)$a[$c]=0;echo join('',array_keys($a)); Shorter and does the same. \$\endgroup\$ – Ismael Miguel 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\$ – Ismael Miguel 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\$ – Fabian Schmengler 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\$ – Ismael Miguel Oct 4 '15 at 20:48
3
\$\begingroup\$

Pyth, 7 bytes

soxzN{z

Pseudocode:

z = input

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

\$\endgroup\$
3
\$\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\$
  • \$\begingroup\$ I had a similar idea but it wasn't as concise. Nice work! \$\endgroup\$ – Alex A. Oct 4 '15 at 17:38
3
\$\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\$
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\$

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\$
  • \$\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\$ – Jerry Jeremiah 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
2
\$\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\$
2
\$\begingroup\$

CJam, 9

Lq{1$-+}/

This doesn't convert a string to a set, but it performs a kind of set difference to determine whether a character is found in a string. Try it online

Explanation:

L       push an empty array/string
q       read the input
{…}/    for each character in the input
  1$    copy the previous string
  -     subtract from the character (set difference),
         resulting in the character or empty string
  +     append the result to the string

Another version, 13 bytes:

Lq{_2$#)!*+}/

This doesn't do anything related to sets. Try it online

Explanation:

L       push an empty array/string
q       read the input
{…}/    for each character in the input
  _     duplicate the character
  2$    copy the previous string
  #)    find the index of the character in the string and increment it
  !     negate, resulting in 0 if the character was in the string and 1 if not
  *     repeat the character that many times
  +     append the result to the string
\$\endgroup\$
2
\$\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\$
2
\$\begingroup\$

Matlab, 46 bytes

It uses an anonymous function, with function arguments as input and output:

@(s)eval('s(~any(triu(bsxfun(@eq,s,s''),1)))')

(I couldn't get this to work in an Octave online interpreter.)

Example use:

>> @(s)eval('s(~any(triu(bsxfun(@eq,s,s''),1)))')
ans = 
    @(s)eval('s(~any(triu(bsxfun(@eq,s,s''),1)))')

>> ans('Type unique chars!')
ans =
Type uniqchars!
\$\endgroup\$
  • \$\begingroup\$ that would have been my idea as well :) - you don't need the ,1 with any, btw. \$\endgroup\$ – Jonas Oct 4 '15 at 20:57
  • \$\begingroup\$ @Jonas Thanks! Alrhough it's hard to see through that mess of parentheses, the 1 is for triu (I need to remove the diagonal), not for any \$\endgroup\$ – Luis Mendo Oct 4 '15 at 22:36
2
\$\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\$
2
\$\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\$
2
\$\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\$

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.