Wpisz uniqchars!

41

Biorąc pod uwagę ciąg znaków składający się z drukowalnych znaków ASCII , uzyskaj wynik składający się z jego unikalnych znaków w oryginalnej kolejności . Innymi słowy, dane wyjściowe są takie same jak dane wejściowe, z wyjątkiem tego, że znak jest usuwany, jeśli pojawił się wcześniej.

Nie można użyć żadnych wbudowanych funkcji wyszukiwania unikalnych elementów w tablicy (na przykład MATLAB ma uniquefunkcję, która to robi). Chodzi o to, aby zrobić to ręcznie.

Dalsze szczegóły:

  • Albo funkcje lub programy są dozwolone.
  • Dane wejściowe i wyjściowe mogą być w postaci argumentów funkcji, stdin / stdout (nawet dla funkcji) lub ich kombinacji.
  • Jeśli używane jest standardowe wejście lub standardowe wyjście, łańcuch jest rozumiany jako sekwencja znaków . Jeśli używane są argumenty funkcji, ciąg znaków, konieczne może być zamknięty w cudzysłowie lub równoważnych symboli języka programowania zastosowań wybór dla definiowania ciągów.
  • Dane wyjściowe powinny być ciągiem zawierającym tylko unikalne znaki danych wejściowych. Więc nie ma żadnych dodatkowych podziałów wierszy, spacji itp. Jedynym wyjątkiem jest: jeśli wyjście jest wyświetlane w stdout, większość funkcji wyświetlania dodaje znak końcowy \n(aby oddzielić ciąg od tego, co będzie dalej). Więc jedno końcowe \njest dopuszczalne na standardowym wyjściu .
  • Jeśli to możliwe, opublikuj link do internetowego interpretera / kompilatora, aby inni mogli wypróbować Twój kod.

To jest kod golfowy , więc wygrywa najkrótszy kod w bajtach.

Kilka przykładów , zakładając stdin i stdout:

  1. Ciąg wejściowy:

    Type unique chars!
    

    Łańcuch wyjściowy:

    Type uniqchars!
    
  2. Ciąg wejściowy

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

    Łańcuch wyjściowy

    "I think'sdarloe,yu
    
  3. Ciąg wejściowy

    3.1415926535897932384626433832795
    

    Łańcuch wyjściowy

    3.14592687
    
Luis Mendo
źródło
5
Wystarczy dwukrotnie sprawdzić: czy reguła no wbudowanych oznacza, że ​​ustawione obiekty są niedozwolone?
Sp3000,
@ Sp3000 Zestaw obiektów jest dozwolony. Po prostu nie używaj funkcji lub metody (jeśli istnieje), która daje ci jej unikalne elementy. A wejście / wyjście powinny być ciągami, a nie ustawionymi obiektami
Luis Mendo,
@ Sp3000 Czy uważasz, że bardziej interesujące byłoby zmniejszenie liczby bajtów o połowę, jeśli nie są używane żadne ustawione funkcje? A może lepiej nie zmieniać zasad po ustaleniu wyzwania?
Luis Mendo,
5
Myślę, że tylko moja odpowiedź używa obecnie zestawów i nie miałbym nic przeciwko, gdybyś to zmienił. Jednak nie jestem pewien, czy taka premia bardzo by się zmieniła, np. Wątpię, aby CJam był wykonalny w <6 bajtach bez zestawów. Poza tym nie jestem pewien, gdzie znajduje się linia między wbudowanym modułem, który znajduje unikalne elementy, a zestawem z wielu elementów ...
Sp3000,
1
@ Sp3000 Tak, to niewyraźna ramka. Nie spodziewałem się ustawić funkcji. Myślę, że odejdę od obecnego wyzwania
Luis Mendo,

Odpowiedzi:

13

GolfScript, 2 bajty

.&

lub alternatywnie:

.|

Opublikowałem to jakiś czas temu w Poradach dotyczących gry w golfa w wątku GolfScript . Działa poprzez duplikowanie ciągu wejściowego (który jest automatycznie umieszczany na stosie przez interpreter GolfScript i który zachowuje się pod wieloma względami jak tablica znaków), a następnie zabranie ze sobą ustawionego przecięcia ( &) lub unii ( |). Zastosowanie operatora zestawu do tablicy (lub łańcucha) powoduje zwinięcie wszelkich duplikatów, ale zachowuje kolejność elementów.

Ilmari Karonen
źródło
23

CJam, 3 bajty

qL|

Ustawione lub danych wejściowych z pustą listą. Operacje na zestawach CJam zachowują kolejność elementów.

Wypróbuj online

Sp3000
źródło
Zakładam, że jest to prawidłowe, ponieważ zestawy są dozwolone, ale nie jestem pewien ...
Sp3000,
Bardzo mądry! Wiedziałem, że CJam będzie jednym z najlepszych, ale nie spodziewałem się tylko 3 bajtów!
Luis Mendo
19

C # 6, 18 + 67 = 85 bajtów

Wymaga tego usingoświadczenia:

using System.Linq;

Rzeczywista metoda:

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

Ta metoda zapisuje niektóre znaki, definiując funkcję jako lambda , która jest obsługiwana w C # 6. Oto jak wyglądałaby w C # przed 6 (ale bez golfa):

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

Jak to działa: wywołuję Wheremetodę na łańcuchu z lambda z dwoma argumentami: xreprezentujący bieżący element, ireprezentujący indeks tego elementu. IndexOfzawsze zwraca pierwszy indeks przekazanego do niego znaku, więc jeśli inie jest równy pierwszemu indeksowi x, jest to duplikat znaku i nie może być uwzględniony.

ProgramFOX
źródło
3
Szczerze mówiąc, nie spodziewałbym się, że C # będzie tak krótki. Świetna robota!
Alex A.,
Uhm. Myślę, że powinieneś przesłać pełny program (z static void Mainitp.).
Timwi,
3
@Timwi To wyzwanie brzmi: „Dozwolone są albo funkcje, albo programy”.
hvd
C # pozwala na krótsze podejście, również przy użyciu LINQ. Opublikowałem konkurencyjną odpowiedź. :)
hvd
@hvd Nice one! +1
ProgramFOX
14

Siatkówka , 14 bajtów

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

Każda linia powinna znajdować się w osobnym pliku lub możesz użyć -sflagi do odczytu z jednego pliku.

Aby to wyjaśnić, użyjemy tej dłuższej, ale prostszej wersji:

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

Pierwszy wiersz to wyrażenie regularne, z którym należy się dopasować ( +`jest to ciąg konfiguracji, który działa do momentu dokonania wszystkich zamian). Wyrażenie regularne szuka znaku (nazywamy go C), po którym następuje zero lub więcej dowolnych znaków, a następnie C. Nawiasy oznaczają przechwytywanie grup, więc zamieniamy dopasowanie na C ( $1) i znaki pomiędzy ( $2), usunięcie duplikatu C.

Na przykład, jeśli ciąg wejściowy był uniquepierwszy bieg będzie pasować uniqu, ze ui niqtak $1i $2, odpowiednio. Zastąpiłby wówczas dopasowany podciąg w oryginalnym wejściu słowem uniq, dając uniqe.

NinjaBearMonkey
źródło
3
Szukałem wyrażenia regularnego, aby to zrobić; Nie zdawałem sobie sprawy, że to było takie krótkie! +1
ETHprodukcje
13

Perl, 21 (20 bajtów + -p)

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

Stosowanie:

perl -pe 's/./!$h{$&}++&&$&/eg' <<< 'Type unique chars!'
Type uniqchars!
Dom Hastings
źródło
1
Możesz zapisać 1 bajt negując $h{$&}i używając logiki ORAZ zamiast operatora trójskładnikowego:s/./!$h{$&}++&&$&/eg
ko
@kos, gdybyś mnie zapytał, powiedziałbym ci, że w 100% próbowałem tego i skończyło się na 1s, ale tak nie jest! Dziękuję, aktualizuję!
Dom Hastings,
1
Głosowałem już :) Myślę, że próbowałeś s/./$h{$&}++||$&/eg(na początku też na to wpadłem). Wstyd, ponieważ byłby to kolejny zapisany bajt.
Kos
11

Makaron 0,02 , 233 bajty

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
  • utwórz język „przeciw golfowi”: sprawdź
  • i tak golf: sprawdź

Jest to pełny program, który wprowadza dane ze STDIN i wyprowadza na STDOUT.

Wersja owinięta, dla wartości estetycznej:

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

I mocno „skomentowana” i nie golfowa wersja (w Macaroni nie ma komentarzy, więc używam po prostu literałów „string”):

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

(To pierwszy prawdziwy program Macaroni (który faktycznie coś robi)! \ O /)

Klamka
źródło
5
• nadaj językowi zabawną i odpowiednią nazwę: sprawdź
Luis Mendo
11

JavaScript ES7, 37 33 25 bajtów

Całkiem proste podejście z wykorzystaniem operatora rozprzestrzeniania się tablic ES6 Seti ES7 :

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

22 bajty mniej niż indexOfpodejście. Pracował nad garstką przypadków testowych.

azz
źródło
Przestrzenie wokół for„s wypowiedzi nie są konieczne i można zrobić to funkcja anonimowa jak niektóre inne rozwiązania nie: s=>[for(c of Set(s))c].join``. (Blada aktualizacja: nie w 100% pewna, ale newsłowo kluczowe wydaje się również niepotrzebne).
manatwork
Nie byłem pewien zasad dotyczących funkcji anonowych i dobrego chwytania przestrzeni.
azz
Transponowany kod bez newskutkował Uncaught TypeError: Constructor Set requires 'new'Google Chrome.
azz
Proszę wybaczyć moją ignorancję, ale w którym momencie filtruje unikalne wartości? Wygląda na to, że po prostu konwertuje ciąg znaków na zestaw na tablicę, a następnie łączy wartości, co powoduje powstanie oryginalnego ciągu.
Patrick Roberts,
@PatrickRoberts to konwersja do zestawu. Zestaw z definicji nie ma duplikatów
edc65
8

C # 6 - 18 + 46 = 64

using System.Linq;

i wtedy

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

Metoda Enumerable.Unionrozszerzenia określa, że ​​elementy są zwracane w oryginalnej kolejności:

Gdy obiekt zwrócony tą metodą jest wyliczany, Union wylicza pierwsze i drugie w tej kolejności i zwraca każdy element, który nie został jeszcze uzyskany.

Operacje na zestawach, które nie są specjalnie przeznaczone do znajdowania unikalnych wartości, wydają się być dozwolone na podstawie innych odpowiedzi.

hvd
źródło
Fajnie, myślałem o string u(string s)=>String.Join("",s.Distinct());tym, ale to trochę dłużej.
germi
@germi Thanks. Odpowiedź była Distinct()już używana , ale została usunięta, ponieważ Distinct()jest niedozwolona w tym wyzwaniu, ponieważ jest to metoda przeznaczona specjalnie do znalezienia unikalnych wartości.
hvd
Ach racja ... przeoczyłem ten kawałek;)
Germi
Jest s => string.Concat(s.Union(s))ważny? Byłby to delegat przekazany Func<string, string>jako argument.
Tyler StandishMan,
@TylerStandishMan Jeśli jest to poprawne, spodziewałbym się, że więcej osób skorzysta z niego, a nie widziałem go wcześniej, więc nie sądzę. Ale może to powinno być poprawne - wydaje się, że warto zainteresować się Metą, jeśli jesteś zainteresowany.
hvd
7

JavaScript ES6, 47 bajtów

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

Poniższy test działa na wszystkich przeglądarkach.

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>

NinjaBearMonkey
źródło
Co robi ta <i?'':eczęść?
DanTheMan,
1
To trójskładnikowy operator. Jeśli pierwsza instancja znaku eznajduje się przed bieżącym indeksem i, zwraca pusty ciąg znaków, w ten sposób usuwając znak. Jeśli jest to pierwsza instancja, po prostu powraca ei nie wprowadza się żadnych zmian.
NinjaBearMonkey
7

MATLAB, 23

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

Wykonuje „set union” ciągu wejściowego z samym sobą, używając metody „stabilnej”, która nie sortuje, a następnie drukuje.

Działa to, ponieważ unionpo scaleniu zwraca tylko niepowielone wartości. Zasadniczo, jeśli unionciąg znaków sam z sobą, najpierw tworzy ciąg podobny do Type unique chars!Type unique chars!, a następnie usuwa wszystkie duplikaty bez sortowania.

Nie ma potrzeby unique:)

Tom Carpenter
źródło
uniqueniedozwolone, przepraszam! Jest w definicji wyzwania
Luis Mendo
Przegapiłem, nieważne.
Tom Carpenter,
W następstwie odpowiedzi SP3000 jest, mogę zasugerować setdiffz 'stable'opcją?
Luis Mendo,
1
Miły! I tak, możesz usunąć, dispponieważ wtedy masz funkcję, która zwraca ciąg znaków, co jest dozwolone
Luis Mendo
1
Możesz także użyć intersectz, 'stable'aby osiągnąć ten sam efekt. Chciałem to napisać, ale biorąc pod uwagę tę odpowiedź, nie jest to już oryginalny lol.
rayryeng - Przywróć Monikę
7

> <> , 16 bajtów

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

> <> nie ma ciągów, więc korzystamy z codbox. Ze względu na toroidalny charakter> <> następujące elementy działają w pętli:

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

Zauważ, że wykorzystuje to fakt, że dane wejściowe zawierają tylko ASCII do wydruku, ponieważ nie działałoby to, gdyby ASCII 0 był obecny.

Sp3000
źródło
1
.......To jest genialne. Chciałbym o tym pomyśleć. W odpowiedzi dołączę wersję Befunge, ale nie podstawową. EDYCJA: Z drugiej strony, to nie zadziała, ponieważ Befunge nie ma nieskończonej przestrzeni kodu. Cholera!
El'endia Starman
@ El'endiaStarman Myślę, że odpowiedź promienia również robi to samo, więc niestety nie mogę powiedzieć, że byłem pierwszy: P
Sp3000
Ahh, tak, myślę, że masz rację. Twoje wyjaśnienie jest jednak jaśniejsze.
El'endia Starman
5

Element , 22 19 18 bajtów

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

Przykładowe wejście / wyjście: hello world->helo wrd

Działa to po prostu przetwarzając ciąg po jednym znaku na raz i śledząc, które widziały wcześniej.

_'{"(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
PhiNotPi
źródło
5

Python 2, 42 bajty

Korzysta z kilku anonimowych funkcji i reduce.

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

Wypróbuj online

mbomb007
źródło
4

Python 3, 44

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

Buduje ciąg wyjściowy rznak po znaku, w tym znak cz danych wejściowych tylko wtedy, gdy go jeszcze nie widzieliśmy.

Python 2 miałby 47 lat, tracąc 4 znaki raw_inputi oszczędzając 1 na niepotrzebnych parers print.

xnor
źródło
Wygląda na to, że obecnie można korzystać inputz Pythona 2, dzięki czemu możesz skrócić bajt.
mbomb007
4

APL, 3

∊∪/

Dotyczy to zjednoczenia (∪) między każdym elementem wektora, uzyskując iterację, która powoduje usunięcie duplikatów.

Przetestuj na tryapl.org

Stary:

~⍨\

Używa ~ (z odwróconymi argumentami, używając ⍨) zastosowanych między każdym elementem argumentu. Powoduje to, że dla każdego elementu, jeśli jest już na liście, jest usuwany.

Moris Zucca
źródło
Nitpicking: „A wejście / wyjście powinny być ciągami znaków”, mówi Luis. „Unione reduk” zwraca zagnieżdżoną tablicę, a nie ciąg znaków. O :-)
lstefano
Masz rację, dodając ∊ na początku, aby poprawić.
Moris Zucca
3

Perl, 54 27 bajtów

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

Test:

$ echo Type unique chars! | perl -e 'map{$h{$_}||=print}<>=~/./g'
Type uniqchars!
$
Steve
źródło
1
print exists($h{$_})?"":$_$h{$_}||print
manatwork
Czy SO wstawił tam znak Unicode → char, co powoduje jego uszkodzenie?
steve
1
użycie modyfikatora instrukcji pozwoli ci zaoszczędzić trochę bajtów wraz z sugestią @ manatwork, $h{$_}||=printa użycie <>=~/./gpowinno pomóc zaoszczędzić jeszcze kilka!
Dom Hastings,
1
Nie, wstawiłem go w znaczeniu „zmień na”.
manatwork
1
Zmiana na mappoprawiłaby również oszczędność: map{$h{$_}||=print}<>=~/./g
manatwork
3

PHP, 72 bajty 84 bajtów

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

Używa znaków jako kluczy dla tablicy asocjacyjnej, a następnie drukuje klucze. Kolejność elementów tablicy jest zawsze kolejnością wstawiania.

Dzięki Ismael Miguel za str_splitsugestię.

Fabian Schmengler
źródło
1
<?foreach(str_split($argv[1])as$c)$a[$c]=0;echo join('',array_keys($a));Krótszy i robi to samo.
Ismael Miguel
Znaleziono krótszy pętli: while($c=$argv[1][$i++*1]). To zastępuje całość foreach. Wszystko inne jest takie samo
Ismael Miguel
Najpierw próbowałem czegoś podobnego, ale powstrzymałem się od tego, ponieważ zatrzymałoby się to na postaci, która wymusza „fałsz”, tj "0". Spróbuj „abc0def” jako danych wejściowych.
Fabian Schmengler,
Masz rację. Z pewnością istnieje obejście tego problemu, które nie kosztuje więcej niż 2 bajty.
Ismael Miguel
3

Pyth, 7 bajtów

soxzN{z

Pseudo kod:

z = wejście

suma wskaźnika uporządkowania według z z N nad zbiorem z.

isaacg
źródło
3

Julia, 45 42 bajtów

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

Stara wersja:

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

Kod buduje nowy ciąg, dodając do niego nowe znaki, a następnie joinłączy je razem w odpowiedni ciąg na końcu. Nowa wersja zapisuje niektóre znaki, wykonując iterację dzięki interpretacji tablic. Zapisuje również bajt przy użyciu ?:zamiast ||(ponieważ eliminuje potrzebę stosowania nawiasów wokół zadania).

Alternatywne rozwiązanie, 45 bajtów, z wykorzystaniem rekurencji i wyrażenia regularnego:

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

Julia, 17 bajtów

(Wersja alternatywna)

s->join(union(s))

Używa się go unionjako substytutu unique- nie uważam tego za „prawdziwą” odpowiedź, ponieważ interpretuję „nie używaj unique” oznacza „nie używaj jednej wbudowanej funkcji, która powoduje zwrócenie unikatowej elementy".

Glen O
źródło
Miałem podobny pomysł, ale nie był tak zwięzły. Dobra robota!
Alex A.,
3

Java, 78 bajtów

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

Prosta pętla podczas sprawdzania wyników dla znaków już obecnych. Akceptuje dane wejściowe jako char[].

Geobity
źródło
3

C, 96 bajtów

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

Wykorzystuje tablicę liczb całkowitych, indeksowanych według numeru znaku ASCII. Znaki są drukowane tylko wtedy, gdy to miejsce w tablicy jest ustawione na FAŁSZ. Po znalezieniu każdego nowego znaku miejsce w tablicy jest ustawione na PRAWDA. Pobiera wiersz tekstu ze standardowego wejścia, zakończony znakiem nowej linii. Ignoruje znaki spoza ASCII.


Nie golfowany:

#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);
}
musarithmia
źródło
3

C - 58

Dzięki @hvd i @AShelly za uratowanie wielu znaków. Sugerowano wiele sposobów, aby uczynić go znacznie krótszym niż oryginał:

// @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;}

Jak widać modyfikowanie w miejscu wydaje się być najkrótsze (jak dotąd!) Program testowy kompiluje się bez użycia ostrzeżeń 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
}

Dzięki za wszelką pomoc. Doceniam wszystkie rady dotyczące skrócenia tak bardzo!

Jerry Jeremiasz
źródło
Dobrze, ponieważ kod nie jest już ważny C, tylko akceptowane przez łagodniejszych kompilatory C: można zadeklarować rjako int(i pominąć int), aby zaoszczędzić kilka bajtów: f(s,r)char*s;{...}. Ale ogranicza twój kod do platform, na których char*jest tego samego rozmiaru int, i oczywiście tam, gdzie kompilatory są tak łagodne jak twoje i moje.
hvd
@hvd To zło! Byłem skłonny ustawić domyślną wartość zwracaną, ponieważ jej nie używam. Ale to trochę bardziej podejrzane niż chciałbym być. Wydaje mi się, że wolałbym uczynić go zgodniejszym niż posunąć się tak daleko! Dzięki za przywrócenie jasnej strony.
Jerry Jeremiah
Możesz uratować jedną if(x)yx?y:0
postać,
Oto funkcja 60 znaków, która zapisuje na standardowe wyjście zamiast parametru tablicy: f(char*s){int a[128]={0};for(;*s;s++)a[*s]++?0:putchar(*s);}
AShelly
Możesz bezwarunkowo kopiować *qi zwiększać tylko, qjeśli postać pojawiła się wcześniej, pozwalając na upakowanie nieco więcej: void f(char*s,char*r){for(char*q=r;*q=*s;strchr(r,*s++)<q||q++);}(Pamiętaj, że strchr(r,*s++)<qzawsze jest dobrze zdefiniowany, nie ma UB, ponieważ strchrnie może wrócić NULLw tej wersji.) Z wyjątkiem typu zwracanego, jest nawet krótszy niż wersja @ AShelly.
hvd,
2

Ruby, 30 24 znaków

(23-znakowy kod + 1-znakowa opcja wiersza poleceń.)

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

Przykładowy przebieg:

bash-4.3$ ruby -pe 'gsub(/./){$`[$&]?"":$&}' <<< 'hello world'
helo wrd
człowiek w pracy
źródło
2

CJam, 9

Lq{1$-+}/

To nie konwertuje ciągu na zestaw, ale wykonuje swoistą różnicę zestawu, aby ustalić, czy znak zostanie znaleziony w ciągu. Wypróbuj online

Wyjaśnienie:

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

Inna wersja, 13 bajtów:

Lq{_2$#)!*+}/

Nie ma to nic wspólnego z zestawami. Wypróbuj online

Wyjaśnienie:

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
aditsu
źródło
2

TI-BASIC, 49 bajtów

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

Zmienne równania są rzadko przydatne, ponieważ zajmują 5 bajtów, ale Y₁przydają się tutaj jako Xth znak ciągu, oszczędzając 3 bajty. Ponieważ nie możemy dodawać do pustych łańcuchów w TI-BASIC, zaczynamy od pierwszego znaku Str1, a następnie zapętlamy resztę łańcucha, dodając wszystkie znaki, których jeszcze nie napotkaliśmy.

prgmQ
?Why no empty st
rings? Because T
I...
Why noemptysrig?Bcau.
lirtosiast
źródło
2

Matlab, 46 bajtów

Używa anonimowej funkcji, z argumentami funkcji jako danych wejściowych i wyjściowych:

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

(Nie mogłem tego uruchomić w internetowym tłumaczu Octave.)

Przykładowe zastosowanie:

>> @(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!
Luis Mendo
źródło
który byłby mój pomysł jak dobrze :) - nie potrzebne ,1przy any, btw.
Jonas
@Jonas Thanks! Chociaż trudno jest przejrzeć ten bałagan w nawiasach, to 1jest dla triu (muszę usunąć przekątną), a nie dlaany
Luis Mendo
2

Befunge -93, 124 bajty

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

Przetestuj to w tym tłumaczu online .


To było trudniejsze niż się spodziewałem. Jutro opublikuję pełniejsze wyjaśnienie, jeśli ktoś tego chce, ale oto przegląd tego, co robi mój kod.

  • Unikalne postacie widoczne do tej pory są przechowywane w pierwszym rzędzie, począwszy od 2,0 i rozciągając w prawo. Jest to sprawdzane w celu sprawdzenia, czy obecny znak jest duplikatem.
  • Liczba unikalnych znaków do tej pory jest przechowywana w, 0,0a licznik pętli sprawdzania duplikatu jest przechowywany w 1,0.
  • Kiedy zobaczysz unikalny znak, jest on zapisywany w pierwszym rzędzie, drukowany, a licznik 0,0jest zwiększany.
  • Aby uniknąć problemów z czytaniem w obecnych spacjach (ASCII 32), umieszczam znak odpowiadający -1 (naprawdę 65536) w następnym miejscu na następny unikalny znak.
El'endia Starman
źródło
2

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]))));

Borta z @ fschmengler za odpowiedź używając array_flipdwukrotnie - drugą wersję wykorzystuje metodę zmienny i zależy od odlewania ciąg true, negując go na false, a następnie rzucając go z powrotem do pustego ciągu w pierwszym argumencie, aby zaoszczędzić kilka bajtów w drugim. Tani!

Niet the Dark Absol
źródło
2

Haskell , 29 bajtów

Jednowierszowy, bez nazwy o zmiennej nazwie:

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

Ta sama liczba zapisana w funkcji o nazwie fjako deklaracja najwyższego poziomu:

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

Zauważ, że istnieje pewna optymistyczna optymalizacja, której nie poczyniłem w duchu dobroci: technicznie nadal jest dozwolone w regułach tego wyzwania użycie innego kodowania wejściowego i wyjściowego dla łańcucha. Reprezentowanie dowolnego stringprzez częściowo zastosowane kodowanie Churcha \f -> foldr f [] string :: (a -> [b] -> [b]) -> [b](z drugą stroną bijectionu zapewnianego przez funkcję ($ (:))) powoduje, że gra się w golfa($ \x->(x:).filter(x/=)) zaledwie 24 znaków.

Unikałem opublikowania 24-znakowej odpowiedzi jako mojej oficjalnej, ponieważ powyższe rozwiązanie można wypróbować na powyższym foldr(\x->(x:).filter(x/=))[]"Type unique chars!"tłumaczu, ponieważ zamiast tego napisano by rozwiązanie w golfa:

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

jako skrót od dosłownej deklaracji, która byłaby bardziej szalona:

($ \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[]

Ale jest to całkowicie poprawna wersja struktury danych reprezentowanej jako czyste funkcje. (Oczywiście możesz również użyć \f -> foldr f [] "Type unique chars!", ale jest to prawdopodobnie nielegalne, ponieważ używa list do faktycznego przechowywania danych, więc jego część składana powinna być prawdopodobnie złożona w funkcję „odpowiadania”, prowadzącą do ponad 24 znaków).

CR Drost
źródło