Dołącz i usuń

14

Biorąc pod uwagę jedną linię, która składa się tylko z liter, wykonaj następujące czynności:

  • Utrzymujesz ciąg pusty na początku.
  • Jeśli następny ciąg wejściowy znajduje się w ciągu, usuń go z ciągu.
  • Jeśli następnego znaku wejściowego nie ma w ciągu, dołącz go do ciągu.

Wyprowadza końcowy stan ciągu.

Możesz bezpiecznie założyć, że dane wejściowe zawierają co najmniej jeden znak (tzn. Niepuste), ale nie ma gwarancji, że dane wyjściowe nie są puste.

Pseudokod (zachęcamy do gry w golfa):

str = EMPTY
for each character ch in input
  if ch exists in str
    remove all ch from str
  else
    append ch to str
print str

Dane wejściowe pasują do wyrażenia regularnego ^[A-Za-z]+$.

Przykładowe przypadki testowe:

ABCDBCCBE -> ADCBE
ABCXYZCABXAYZ -> A
aAABBbAbbB -> aAbB
GG -> (empty)

Dane wejściowe można podać w dowolny odpowiedni sposób, ale należy je traktować jako ciąg znaków i to samo dla danych wyjściowych. Program nie powinien wychodzić z błędem.

Zwycięża najkrótszy program w każdym języku!

Dodatkowe (opcjonalne): wyjaśnij, jak działa Twój program. Dziękuję Ci.

iBug
źródło
Czy linia może być pusta?
user202729,
1
@ user202729 Nie. Zmieniłem trochę (nie unieważnia żadnej odpowiedzi), więc dane wejściowe nigdy nie są puste.
iBug
1
Dlaczego więc odrzuciłeś sugestię edycji ais523 (link) ?
user202729,

Odpowiedzi:

10

Haskell , 44 42 bajty

foldl(#)""
s#x|z<-filter(/=x)s=z++[x|z==s]

Wypróbuj online! Edycja: -2 bajty dzięki Zgarb!

Wyjaśnienie:

Druga linia definiuje funkcję, (#)która pobiera ciąg znaków si znak xi wykonuje operację usuwania lub dołączania. Osiąga się to przez filterwygaszenie każdego wystąpienia xin s, co powoduje powstanie ciągu z. Jeśli xnie występuje w s, to zjest równe si z++[x|z==s]zwraca oryginalny ciąg z xdołączonym. W przeciwnym razie [x|z==s]zwraca pusty ciąg i zwracany jest tylko ciąg filtrowany.

foldl(#)""jest anonimową funkcją, która pobiera ciąg znaków i dodaje jeden znak po drugim początkowo pusty ciąg ""z funkcją (#).

Laikoni
źródło
2
42 bajty przez ponowne użycie filtra.
Zgarb
9

Galaretka , 3 bajty

œ^/

Wypróbuj online!

Pełny program

Erik the Outgolfer
źródło
Dlaczego to œ^/nie wystarczy?
Jonathan Allan
@JonathanAllan Program nie powinien
Erik the Outgolfer
the input is never emptyCóż, teraz to działa.
user202729,
8

J , 21 19 bajtów

#~~:&.|.(2|*)1#.=/~

Jak to działa:

=/~ - tworzy tabelę równości znaków w ciągu:

   a =. 'ABCXYZCABXAYZ'
   ]b =: =/~ a 
1 0 0 0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 0 0 0 1
0 0 1 0 0 0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 0 1 0 0 1 0 0
0 0 0 0 1 0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 0 0 0 1

1#. - suma każdego wiersza według przelicznika podstawowego 1 (ile razy litera występuje)

   ]c =: 1#. b
3 2 2 2 2 2 2 3 2 2 3 2 2

~:&.|- odwróć, następnie zastosuj sito nub (unikalny jest char) i odwróć ponownie. W ten sposób znajduję ostatnie wystąpienia znaków w ciągu:

   ]d =. ~:&.|. a
0 0 0 0 0 0 1 0 1 1 1 1 1

* - mnoży liczbę przez 1 dla ostatniej pozycji znaku w sringu, przez 0 w przeciwnym razie, obliczoną przez powyższe ~:&.|

   ]e =. c * d
0 0 0 0 0 0 2 0 2 2 3 2 2

2| - moduł 2 (ustawia na 0 pozycje znaków, które się liczą):

   ]f =. 2| e 
0 0 0 0 0 0 0 0 0 0 1 0 0

#~- skopiuj prawy argument left arg. razy (~ odwraca miejsca argumentów)

]f # a A

Wypróbuj online!

Galen Iwanow
źródło
6

Brainfuck, 95 bajtów

,[<<<[[->+>>>+<<<<]>>>[-<+<->>]<<[[-]<]>[[-]>>[-]>[[-<+>]>]<<[<]<<]<<]<[->>>>[-]<<<]>>>>[->+<]>>[>]>>,]<<<[.<]

Wypróbuj online

Jak to działa

, Gets first input
[ Starts loop
    <<< Go to start of string
    [ Loop over the string
        [->+>>>+<<<<] Duplicates the current char of the string
        >>>[-<+<->>] Duplicates and subtracts the inputted char from the duplicate of the string char
        <<[[-]<] If the char is different to the input, remove the difference
        > If the char is the same
        [
            [-]>>[-]>[[-<+>]>]<<[<]<< Remove the char from the string and sets the inputted char to 0
        ]
        << Moves to the next char of the string
    ]
    >>>[->+<] adds the inputted char to the string
    >>[>]>>, gets the next input
]
<<<[.<] prints the string
Jo King
źródło
4

Haskell , 47 bajtów

Kolejny bajtuje kurz dzięki Bruce'owi Forte.

import Data.List
foldl1(\x y->union(x\\y)$y\\x)

Wypróbuj online!

Pobiera listę ciągów.

Różnica symetryczna jest denerwująca ...

całkowicie ludzki
źródło
++uniondzięki tej metodzie oszczędza 2 bajty .
Ørjan Johansen
2

R , 92 84 77 bajtów

for(i in el(strsplit(scan(,y<-''),y)))y=c(y[y!=i],if(!i%in%y)i);cat(y,sep='')

Wypróbuj online!

-15 bajtów dzięki djhurio

Wyjaśnienie

djhurio zapewnił doskonałą odpowiedź R, unikając forpętli - jak programiści R instynktownie robią z reguły (łącznie ze mną). Oto odpowiedź R, która wykorzystuje forpętlę (i zapisuje kilka bajtów w procesie).

  • x=scan(,''); - przypisz dane wejściowe do zmiennej x
  • y=''; - utwórz pusty ciąg w zmiennej o nazwie y
  • for(i in el(strsplit(x,'')))- dla każdej postaci iwx
  • y=c(y[y!=i],if(!i%in%y)i)- przypisać do ykażdego elementu, yktóry nie jest równy i, dołączając, ijeśli jeszcze igo nie byłoy
  • cat(y,sep='')- wydrukuj elementy ybez odstępu między nimi

Uwaga

Jeśli klikniesz powyższy link TIO, znajdziesz w nagłówku library(methods); ma to na celu rozwiązanie błędu djhurio występującego w związku z el()funkcją - funkcja jest dostarczana przez methodspakiet, który w dowolnej wersji R, z której korzystałem, jest domyślnie ładowany, ale z jakiegokolwiek powodu nie jest to TIO. Jeśli library(methods)zostanie usunięty z nagłówka i unlistzastąpiony el, zyskuję cztery bajty, ale tak też zrobi djhurio , ustawiając liczbę naszych bajtów odpowiednio na 96 88 i 99.

duckmayr
źródło
Niezłe. Nigdy nie myślałem, że pętla będzie krótsza. Możesz go jeszcze skrócić, pomijając instrukcję else for(i in el(strsplit(scan(,y<-''),y)))y=c(y[y!=i],if(!i%in%y)i);cat(y,sep='').
djhurio
@ djhurio - Wiem, prawie nigdy nie jest tak, że w R a for loop pomoże w czymkolwiek. Jeśli chodzi o twoją sugestię: świetny pomysł! Sugestia została uwzględniona w odpowiedzi.
duckmayr
1
@djhurio - wystarczy; Byłem zbyt zajęty patrzeniem na różnicę wprowadzoną przez pominięcie oświadczenia else. Nie widziałem, jak zmieniłeś początek. Edycja teraz. Świetna robota!
duckmayr
1
@djhurio @duckmayr istnieje 73-bajtowe rozwiązanie, które zasadniczo bierze to rozwiązanie i stosuje nieco inne podejście do wydobywania znaków. Tak naprawdę nie miałem ochoty publikować tego jako osobnej odpowiedzi. Należy również pamiętać, że ...[[1]]jest dłuższy niż, el(...)ale krótszy niż unlist(...), pod warunkiem, że ...jest to lista długości 1.
Giuseppe,
1
podrap to, znalazłem 70-bajkową odpowiedź, ponieważ 0jest to nulznak i zostaje przekonwertowany na pusty ciąg.
Giuseppe,
2

MATL , 6 bajtów

vi"@X~

Nie działa w środowisku TIO, ale działa dobrze w implementacji MATLAB, a dzięki nowej łatce możesz wypróbować ją w MATL Online

X~jest równa setxorlub różnica symetryczna, co robi dokładnie to, o co prosi wyzwanie. Reszta po prostu zapętla dane wejściowe i"@i zaczyna od pustego łańcucha, łącząc cały stos, który jest pusty na początku (dzięki Luis Mendo).

Sanchises
źródło
2

Python 2 , 56 bajtów

-2 bajty dzięki xnor. -3 bajty dzięki ovs.

lambda s:reduce(lambda a,c:a.replace(c,'')+c[c in a:],s)

Wypróbuj online!

Dosłownie właśnie grałem w pseudokod. : P

całkowicie ludzki
źródło
1
Zaoszczędzić 2 bajty: s=(s+c).replace(c,c[c in s:]).
xnor
@xnor To podstawowa gra w golfa wykonana bardzo sprytnie. Dzięki!
całkowicie ludzki,
1
-1 bajt :s=s.replace(c,'')+c[c in s:]
ov
1
56 bajtów przy użyciu zmniejszania
ov
1

JavaScript (ES6), 60 bajtów

s=>[...s].map(c=>s=s.match(c)?s.split(c).join``:s+c,s='')&&s

Przypadki testowe

Arnauld
źródło
Przesłałem odpowiedź Retina @ MartinEndera i miała ona tylko 45 bajtów ...
Neil,
1

q , 38 bajtów

""{$[y in x;except;,][x;y]}/
skeevey
źródło
1

APL + WIN, 19 bajtów

Logika podobna do rozwiązania J Galena.

(2|+⌿⌽<\⌽c∘.=c)/c←⎕     
Graham
źródło
1

Wolfram Language (Mathematica) , 36 bajtów

#//.{a___,x_,b___,x_,c___}:>{a,b,c}&

Wypróbuj online!

Pobiera dane wejściowe i wyjściowe jako listę znaków.

Jak to działa

Używa //.(aliasu ReplaceRepeated), aby znaleźć dwa powtarzające się znaki i usunąć oba, dopóki nie będzie już więcej powtarzających się znaków. Jeśli postać występuje więcej niż dwa razy, Mathematica zawsze usunie pierwsze dwa wystąpienia. Jeśli więc postać pojawi się nieparzystą liczbę razy, jej ostatnią instancją zawsze będzie ta, która przeżyje.

Misza Ławrow
źródło
1

Prolog 81 bajtów

a([],O,O).
a([I|J],K,O):-delete(K,I,F),(K=F->append(K,[I],M),a(J,M,O);a(J,F,O)).

Wersja nie zaciemniona:

append_and_eraze([], Output, Output).
append_and_eraze([I | Input], Interim, Output) :-
    delete(Interim, I, Filtered),
    ( Interim = Filtered ->
      append(Interim, [I], Interim1),
      append_and_eraze(Input, Interim1, Output)
    ;
    append_and_eraze(Input, Filtered, Output)
    ).
  1. delete/3 zapewnia, że ​​jego trzeci argument ujednolica się z pierwszym argumentem, a wszystkie wystąpienia drugiego argumentu zostaną z niego usunięte.
  2. Jeśli okażą się takie same, dodajemy element (nie został usunięty).
  3. append/3 jak sama nazwa dołącza element do listy.
  4. Powtarzamy na elementach wejściowych, aż trafimy na [](pustą listę), w którym to momencie wynik pośredni zostanie zjednoczony z pożądanym wynikiem.

Test:

?- append_and_eraze(`ABCDBCCBE`, [], X), string_codes(Y, X).
X = [65, 68, 67, 66, 69],
Y = "ADCBE".

?- append_and_eraze(`ABCXYZCABXAYZ`, [], X), string_codes(Y, X).
X = [65],
Y = "A".

?- append_and_eraze(`aAABBbAbbB`, [], X), string_codes(Y, X).
X = [97, 65, 98, 66],
Y = "aAbB".

?- append_and_eraze(`GG`, [], X), string_codes(Y, X).
X = [],
Y = "".

Niektóre Prologi traktują ciągi w podwójnych cudzysłowach jak listy, SWI można skonfigurować tak, aby robił to samo, ale dla uproszczenia string_codes/2ładnie sformatowałem dane wyjściowe.

wvxvw
źródło
1

R , 84 bajtów

y=el(strsplit(scan(,""),""));cat(unique(y[colSums(outer(y,y,"=="))%%2>0],,T),sep="")

Wypróbuj online!

Inne rozwiązanie, ale tutaj są lepsze odpowiedzi R.

R , 88 bajtów

z=table(y<-el(strsplit(scan(,""),"")));cat(setdiff(unique(y,,T),names(z[!z%%2])),sep="")

Wypróbuj online!

Dzięki Giuseppe za -7 bajtów!

Odpowiedź kaczki jest krótsza .

  1. scan(,"") odczytać wejście ze standardowego wejścia.
  2. y<-el(strsplit(scan(,""),""))podziel wprowadzanie na znaki i zapisz jako y.
  3. z=table(y<-el(strsplit(scan(,""),"")))oblicz częstotliwości każdego znaku i zapisz wynikową tabelę jako z;
  4. unique(y,,T) zabierz unikalne postacie z prawej strony.
  5. names(z[!z%%2]) wybierz tylko parzyste liczby i wyodrębnij nazwy.
  6. setdiff(unique(y,,T),names(z[!z%%2])) usuń postacie z parzystą liczbą.
  7. cat(setdiff(unique(y,,T),names(z[!z%%2])),sep="") wydrukować wynik.
djhurio
źródło
Przyczyną twojego błędu jest to, że el()pochodzi on z methodspakietu, który choć zwykle ładowany jest domyślnie, nie jest TIO (omówiony w mojej odpowiedzi poniżej)
duckmayr
dlaczego używasz rev(unique(rev(y)))? Czy po prostu nie unique(y)zadziała? ooohhh czekaj, rozumiem, chcesz unikalne postacie od prawej do lewej. W takim przypadku unique(y,,T)(ustawienie fromLast=T) wyniesie 88 bajtów .
Giuseppe,
0

Alice , 9 bajtów

/X&@
\io/

Wypróbuj online!

Wyjaśnienie

Zasadniczo port odpowiedzi Erika . Poza odrobiną przekierowania adresu IP kod jest po prostu:

i&Xo@

co robi:

i   Read all input.
&X  Fold symmetric multiset difference over the input.
o   Output the result.
@   Terminate.
Martin Ender
źródło
0

APL (Dyalog) , 16 bajtów

{(,⍨~∩)/⍣(≢⍵)⊖⍵}

Wypróbuj online!

Gdyby błędy były dozwolone, byłoby to 9 bajtów:

(,⍨~∩)/∘⊖
Erik the Outgolfer
źródło
Co rozumiesz przez błędy?
FrownyFrog,
@FrownyFrog 9-bajtowa wersja wyrzuciłaby a, DOMAIN ERRORjeśli ciąg jest pusty, ponieważ (,⍨~∩)nie ma predefiniowanego elementu tożsamości.
Erik the Outgolfer
0

Rubin , 53 bajty

->s{s.reverse.uniq.select{|c|s.count(c)%2>0}.reverse}

Wypróbuj online!

Dane wejściowe i wyjściowe są tablicą znaków. Testuj połączenia kodowe .charsi .joindla wygody.

Wyjaśnienie

Wykorzystuje fakt, że litery w wynikowym ciągu pojawiają się nieparzystą liczbę razy i w kolejności od prawej do lewej.

->s{                # lambda function taking char-array argument
    s.reverse           # reverse the input
    .uniq               # get unique characters
    .select{|c|         # select only those which...
        s.count(c)%2>0      # appear in the input array an odd number of times
    }.reverse           # reverse back and return
}
Justin Mariner
źródło
0

Pyth, 13 bajtów

{_xD_Qf%/QT2Q

Pobiera dane wejściowe jako listę znaków. Przetestuj to!

      f     Q            (f)ilter input (Q)
        /QT              On how many times (/) each character (T) appears in the 
                           input (Q)
       %   2             Only allow odd numbers of occurences (when x % 2 = 1)
 _xD_Q                   Sort (D) descending (the first _) by the location (x) of 
                           the last (the second _) inde(x) of the target character
                           in the input (Q)
{                        Remove duplicates
Steven H.
źródło
0

Röda , 34 bajty

{a=[]a-=_ if[_1 in a]else a+=_1;a}

Wypróbuj online!

To jest bezpośrednie tłumaczenie pseudokodu. Traktuje dane wejściowe i wyjściowe jako strumienie znaków.

Wyjaśnienie:

{                    /* Anonymous function                   */
    a=[]             /* initialize a                         */
                     /* For each character _1 in the stream: */
    a-=_ if[_1 in a] /*  Remove it from a if a contains it   */
    else a+=_1;      /*  Otherwise append it to a            */
    a                /* Push characters in a to the stream   */
}
fergusq
źródło
0

Python 3 , 73 bajty

Nie najkrótszy, ale podoba mi się to podejście.

lambda s:''.join(c*(s.count(c)%2)*(i==s.rfind(c))for i,c in enumerate(s))

Wypróbuj online!

Pętle przechodzą przez ciąg, zachowując tylko te znaki, w których:

  • (s.count(c)%2) == 0 - Postać pojawia się parzysta liczba razy.
  • (i==s.rfind(c)) - Obecny indeks jest ostatnim pojawieniem się danej postaci.
FlipTack
źródło
0

REXX , 102 bajty

a=arg(1)
s=''
do while a>''
  b=right(a,1)
  if countstr(b,a)//2 then s=b||s
  a=changestr(b,a,'')
  end
say s

Wypróbuj online!

Jak to działa: weź prawą literę, zobacz, czy liczba wystąpień jest parzysta czy nieparzysta (która również podwaja się jako wartość prawdy), a jeśli nieparzysta, dodaj ją do ciągu wyjściowego. Następnie usuń wszystkie wystąpienia litery z ciągu wejściowego. Powtarzaj do momentu wyczerpania się danych wejściowych.

idrougge
źródło
0

Java 8, 93 bytes

A lambda from String to String. Just an implementation of the pseudocode in the question.

s->{String o="";for(char c:s.toCharArray())o=o.indexOf(c)<0?o+c:o.replace(c+"","");return o;}

Try It Online

Java 8, 182 bytes

Here's another lambda of the same type that uses streams! It's probably more efficient.

s->s.join("",s.chars().mapToObj(c->(char)c+"").filter(c->s.replaceAll("[^"+c+"]","").length()%2>0).distinct().sorted((c,d)->s.lastIndexOf(c)-s.lastIndexOf(d)).toArray(String[]::new))

Try It Online

Ungolfed

s ->
    s.join(
        "",
        s.chars()
            .mapToObj(c -> (char) c + "")
            .filter(c -> s.replaceAll("[^" + c + "]", "").length() % 2 < 0)
            .distinct()
            .sorted((c, d) -> s.lastIndexOf(c) - s.lastIndexOf(d))
            .toArray(String[]::new)
    )
Jakob
źródło
0

R, 70 bytes

function(s){for(i in utf8ToInt(s))F=c(F[F!=i],i*!i%in%F);intToUtf8(F)}

Try it online!

I was encouraged by djhurio to post this solution; djhurio's answer can be found here.

This uses the same idea as duckmayr's answer, but it leverages a numeric approach by converting the string to its codepoints rather than splitting it into characters, and is a function rather than a full program so it can return the new string rather than printing to stdout.

function(s) {
 for(i in utf8ToInt(s))           # convert string to codepoints and iterate over it
  F=c(F[F!=i],                    # remove duplicates and append
      i*!i%in%F)                  # 0 if in F, i otherwise
 intToUtf8(F)                     # collapse from codepoints to string
}

One important observation is that F is initialized to FALSE or 0 and utf8ToInt(0)=="", so this will succeed for the empty string as well as correctly collapsing the codepoints.

Giuseppe
źródło
0

PHP, 71+1 bytes

while(~$c=$argn[$i++])$s=strstr($s,$c)?strtr($s,[$c=>""]):$s.$c;echo$s;

Run as pipe with -nR or try it online.

Titus
źródło
0

Python 3.6, 69 bytes

lambda a:"".join({c:1 for c in a[::-1] if a.count(c)%2}.keys())[::-1]

Try it online!

Dict insertion order is preserved in Python 3.6 .

user285259
źródło
0

SNOBOL4 (CSNOBOL4), 97 95 bytes

	S =INPUT
N	S LEN(1) . C REM . S :F(O)
	O C :S(R)
	O =O C :(N)
R	O C =:S(R)F(N)
O	OUTPUT =O
END

Try it online!

	S =INPUT			;* read input
N	S LEN(1) . C REM . S :F(O)	;* take the first character of S and assign it to C,
					;* assign the remainder to S, and if S has no characters left, goto O
	O C :S(R)			;* if C matches anything in O, goto R, otherwise go to next line
	O =O C :(N)			;* append C to O and goto N
R	O C =:S(R)F(N)			;* as long as C matches O, replace it with ''
					;* (unassigned variables default to the null string)
					;* then goto N once it fails to match
O	OUTPUT =O			;* output the string
END					;* terminate the program
Giuseppe
źródło