Добавить и стереть

14

Учитывая одну строку, которая состоит только из букв, обработайте следующим образом:

  • Вы поддерживаете пустую строку в начале.
  • Если следующий входной символ находится в строке, удалите его из строки.
  • Если следующего входного символа нет в строке, добавьте его в строку.

Выведите окончательное состояние строки.

Вы можете смело предположить, что входные данные состоят как минимум из одного символа (то есть непустого), но нет гарантии, что выходные данные не пусты.

Псевдокод (не стесняйтесь играть в гольф):

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

Ввод соответствует регулярному выражению ^[A-Za-z]+$.

Примеры тестовых случаев:

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

Входные данные могут быть заданы любым применимым способом, но они должны рассматриваться как строка и то же самое для выходных данных. Программа не должна выходить с ошибкой.

Победит самая короткая программа на каждом языке!

Дополнительно (необязательно): пожалуйста, объясните, как работает ваша программа. Спасибо.

iBug
источник
Может ли строка быть пустой?
user202729
1
@ user202729 Нет. Я немного изменился (это не отменяет никакого ответа), поэтому ввод никогда не бывает пустым.
iBug
1
Так почему же вы отклонили предложение по редактированию ais523 (ссылка) ?
user202729

Ответы:

10

Haskell , 44 42 байта

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

Попробуйте онлайн! Редактировать: -2 байта благодаря Zgarb!

Объяснение:

Вторая строка определяет функцию, (#)которая принимает строку sи символ xи выполняет удаление или добавление. Это достигается путем filterисключения каждого вхождения xin s, в результате чего получается строка z. Если xне встречается в s, то zравно sи z++[x|z==s]возвращает исходную строку с xдобавлением. В противном случае [x|z==s]выдает пустую строку и возвращается только отфильтрованная строка.

foldl(#)""является анонимной функцией, которая берет строку и добавляет один символ за другим изначально пустую строку ""с функцией (#).

Laikoni
источник
2
42 байта путем повторного использования фильтра.
Згарб
9

Желе , 3 байта

œ^/

Попробуйте онлайн!

Полная программа.

Эрик Outgolfer
источник
Почему œ^/не достаточно?
Джонатан Аллан
@JonathanAllan Программа не должна выходить с ошибкой.
Эрик Outgolfer
the input is never emptyНу, теперь это работает.
user202729
8

J , 21 19 байт

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

Как это устроено:

=/~ - составляет таблицу равенства символов в строке:

   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#. - сумма каждой строки по конверсии по основанию 1 (сколько раз встречается буква)

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

~:&.|- переверните, затем примените сито (это уникальный символ) и снова переверните. Таким образом я нахожу последние вхождения символов в строке:

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

* - умножает счет на 1 для последней позиции символа в строке, на 0 в противном случае, рассчитывается по вышеуказанному ~:&.|

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

2| - по модулю 2 (устанавливает в 0 позиции символов с четным счетом):

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

#~- скопировать правый аргумент в левый аргумент. времена (~ меняет местами арги)

]f # a A

Попробуйте онлайн!

Гален Иванов
источник
6

Brainfuck, 95 байт

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

Попробуйте онлайн

Как это устроено

, 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
Джо Кинг
источник
4

Haskell , 47 байтов

Еще один байт пыли благодаря Брюсу Форте.

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

Попробуйте онлайн!

Принимает список строк.

Симметричная разница раздражает ...

totallyhuman
источник
++unionс помощью этого метода экономит 2 байта .
Орджан Йохансен
2

R , 92 84 77 байт

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

Попробуйте онлайн!

-15 байт благодаря джурио

объяснение

djhurio предоставил отличный ответ R, избегая forпетли - как обычно делают программисты R (включая меня). Вот ответ R, который использует forцикл (и сохраняет несколько байтов в процессе).

  • x=scan(,''); - назначить вход в переменную x
  • y=''; - создать пустую строку в переменной с именем y
  • for(i in el(strsplit(x,'')))- для каждого персонажа iвx
  • y=c(y[y!=i],if(!i%in%y)i)- присваивать yкаждому элементу, yкоторый не равен i, добавление, iесли еще iне былоy
  • cat(y,sep='')- печатать элементы yбез пробелов между ними

Заметка

Если вы нажмете ссылку TIO выше, вы найдете в заголовке library(methods); это связано с ошибкой djhurio, возникшей в отношении el()функции - функция предоставляется methodsпакетом, который в любой версии R, которую я использовал, загружается по умолчанию, но по какой-то причине не TIO. Если library(methods)удалить из заголовка и unlistзаменить его el, я получу четыре байта, но так же, как и djhurio , выставив наши байты в 96, 88 и 99 соответственно.

duckmayr
источник
Хороший. Никогда не думал, что петля будет короче. Вы можете сделать его еще короче, пропустив оператор else for(i in el(strsplit(scan(,y<-''),y)))y=c(y[y!=i],if(!i%in%y)i);cat(y,sep='').
Джурио
@djhurio - я знаю, что почти никогда не случается, что в цикле R a for что-нибудь поможет. По поводу вашего предложения: отличная идея! Предложение теперь включено в ответ.
duckmayr
1
@djhurio - достаточно честно; Я был слишком занят, глядя на разницу, представленную пропущенным оператором else, я не видел, как вы изменили начало. Редактирование сейчас. Отличная работа!
duckmayr
1
@djhurio @duckmayr есть 73-байтовое решение , которое в основном использует это решение и использует несколько иной подход к извлечению символов. Я действительно не хотел публиковать его как отдельный ответ. Также обратите внимание, что ...[[1]]это длиннее, el(...)но короче unlist(...), при условии, что ...это список длиной 1.
Джузеппе
1
поцарапайте это, я нашел ответ 70 пока, так 0как nulсимвол и преобразован в пустую строку.
Джузеппе
2

MATL , 6 байтов

vi"@X~

Не работает в среде TIO, но отлично работает с реализацией MATLAB, и, благодаря свежему патчу , вы можете попробовать его на MATL Online

X~равно setxorили симметричная разница, которая делает именно то, что просит задача. Остальное просто зацикливается на вводе i"@и начинается с пустой строки путем объединения всего стека, который пуст в начале (спасибо Луису Мендо).

Sanchises
источник
2

Python 2 , 56 байт

-2 байта благодаря xnor. -3 байта благодаря овс.

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

Попробуйте онлайн!

Буквально только что поиграл в псевдокод. :П

totallyhuman
источник
1
Сохранить 2 байта: s=(s+c).replace(c,c[c in s:]).
xnor
@xnor Это очень умная игра в гольф. Благодарность!
полностью человек
1
-1 байт :s=s.replace(c,'')+c[c in s:]
ОВС
1

JavaScript (ES6), 60 байт

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

Контрольные примеры

Arnauld
источник
Я портировал ответ Retina @ MartinEnder, и он был только 45 байтов ...
Нил
1

APL + WIN, 19 байт

Логика похожа на решение Галена.

(2|+⌿⌽<\⌽c∘.=c)/c←⎕     
Грэхем
источник
1

Wolfram Language (Mathematica) , 36 байт

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

Попробуйте онлайн!

Принимает ввод и вывод в виде списка символов.

Как это устроено

Использует //.(псевдоним ReplaceRepeated), чтобы найти два повторяющихся символа и удалить оба, пока повторных символов больше не будет. Если персонаж встречается более двух раз, Mathematica всегда удаляет первые два вхождения. Поэтому, если персонаж встречается нечетное количество раз, его последним всегда будет тот, кто выживет.

Миша лавров
источник
1

Пролог 81 байт

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)).

Не запутанная версия:

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 гарантирует, что его третий аргумент объединяется с его первым аргументом, и все экземпляры второго аргумента удаляются из него.
  2. Если они оказываются одинаковыми, мы добавляем элемент (он не был удален).
  3. append/3 согласно его имени, добавляет элемент в список.
  4. Мы повторяем элементы ввода до тех пор, пока не достигнем [](пустой список), после чего промежуточный результат объединится с желаемым результатом.

Тестовое задание:

?- 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 = "".

Некоторые прологи обрабатывают строки в двойных кавычках как списки, SWI может быть настроен на то же самое, но для простоты я привык string_codes/2красиво форматировать вывод.

wvxvw
источник
1

R , 84 байта

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

Попробуйте онлайн!

Другое решение, но есть лучшие ответы R здесь.

R , 88 байт

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

Попробуйте онлайн!

Спасибо Джузеппе за -7 байт!

Есть более короткий ответ от Duckmayr .

  1. scan(,"") читать ввод из стандартного ввода.
  2. y<-el(strsplit(scan(,""),""))разделить ввод по символам и сохранить как y.
  3. z=table(y<-el(strsplit(scan(,""),"")))вычислить частоты каждого символа и сохранить полученную таблицу как z;
  4. unique(y,,T) возьмите уникальных персонажей с правой стороны.
  5. names(z[!z%%2]) выбрать только четные числа и извлечь имена.
  6. setdiff(unique(y,,T),names(z[!z%%2])) удалить символы с четным количеством.
  7. cat(setdiff(unique(y,,T),names(z[!z%%2])),sep="") распечатать вывод.
djhurio
источник
Причиной вашей ошибки является то, что она el()исходит из methodsпакета, который обычно загружается по умолчанию, но не TIO (об этом рассказано в моем ответе ниже)
duckmayr
почему вы используете rev(unique(rev(y)))? Не будет просто unique(y)работать? оооооооооо, я вижу, вы хотите уникальные символы справа налево. В этом случае unique(y,,T)(настройка fromLast=T) будет 88 байтов .
Джузеппе
0

Алиса, 9 bytes

/X&@
\io/

Try it online!

Explanation

В основном порт ответа Эрика . Помимо небольшого перенаправления IP-кода код действительно просто:

i&Xo@

который делает:

i   Read all input.
&X  Fold symmetric multiset difference over the input.
o   Output the result.
@   Terminate.
Martin Ender
источник
0

APL (Dyalog), 16 bytes

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

Try it online!

If errors were allowed, this would've been 9 bytes:

(,⍨~∩)/∘⊖
Erik the Outgolfer
источник
What do you mean by errors?
FrownyFrog
@FrownyFrog The 9-byte version would throw a DOMAIN ERROR if the string is empty, since (,⍨~∩) doesn't have a predefined identity element.
Erik the Outgolfer
0

Ruby, 53 bytes

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

Try it online!

Input and output are both an array of chars. Test code calls .chars and .join for convenience.

Explanation

Uses the fact that the letters in the resulting string appear an odd number of times and in the order from right to left.

->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
источник
0

Pyth, 13 bytes

{_xD_Qf%/QT2Q

Takes in input as list of characters. Test it out!

      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.
источник
0

Röda, 34 bytes

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

Try it online!

This is a direct translation of the pseudocode. It treats input and output as streams of characters.

Explanation:

{                    /* 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
источник
0

Python 3, 73 bytes

Not the shortest, but I like this approach.

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

Try it online!

Loops through the string, keeping only those characters where:

  • (s.count(c)%2) == 0 - The character appears an even number of times.
  • (i==s.rfind(c)) - The current index is the last appearance of the character in question.
FlipTack
источник
0

REXX, 102 bytes

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

Try it online!

How it works: Take the rightmost letter, see if the number of occurrences is even or odd (which also doubles as a truth value) and if odd, add it to the output string. Then remove all occurrences of the letter from the input string. Repeat until input is depleted.

idrougge
источник
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
источник
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
источник
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
источник
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
источник