Додавання та стирання


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)

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

Виграє найкоротша програма з кожної мови!

Додатково (необов’язково): Поясніть, як працює ваша програма. Дякую.


Може рядок буде порожнім?
користувач202729

1
@ user202729 Ні. Я трохи змінив (це не визнає недійсною відповідь), щоб вхід ніколи не був порожнім.
iBug

1
То чому ви відхилили пропозицію редагування (посилання) на ais523 ?
користувач202729

Відповіді:


10

Хаскелл , 44 42 байти

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

Спробуйте в Інтернеті! Редагувати: -2 байти завдяки Zgarb!

Пояснення:

Другий рядок визначає функцію, (#)яка приймає рядок sі символ xі виконує або видалити, або додати. Це досягається шляхом filterвиведення кожного появи xв s, в результаті чого рядок z. Якщо xцього не відбувається s, то zдорівнює sі z++[x|z==s]виходить початковий рядок із xдоданим. В іншому випадку [x|z==s]виходить порожній рядок і повертається лише відфільтрована рядок.

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


2
42 байти шляхом повторного використання фільтра.
Згарб


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



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

Пояснення

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 відповідно.


Хороший. Ніколи не думав, що петля буде коротшою. Ви можете зробити її ще коротшою, опустивши оператор else for(i in el(strsplit(scan(,y<-''),y)))y=c(y[y!=i],if(!i%in%y)i);cat(y,sep='').
djhurio

@djhurio - Я знаю, майже ніколи не буває так, що в R a for цикл допоможе будь-чим. Щодо вашої пропозиції: Чудова ідея! Пропозиція тепер включена у відповідь.
duckmayr

1
@djhurio - досить справедливо; Я був надто зайнятий переглядом різниці, введеної опущеним іншим твердженням, я не бачив, як ви змінили початок. Редагування зараз. Чудова робота!
дакмайер

1
@djhurio @duckmayr є 73- байтне рішення, яке в основному приймає це рішення і використовує дещо інший підхід до вилучення символів. Я не дуже хотів розміщувати це як окрему відповідь. Також зауважте, що ...[[1]]довше, el(...)але коротше, за unlist(...)умови, що ...це список довжини 1.
Джузеппе

1
Подразумніть це, я знайшов відповідь 70 бай, оскільки 0є nulсимволом і перетворюється на порожній рядок.
Джузеппе

2

MATL , 6 байт

vi"@X~

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

X~дорівнює setxor, або симетрична різниця, яка робить саме те, що задається завданням. Решта - просто перекидання на вхід i"@і починаючи з порожнього рядка, об'єднуючи весь стек, який порожній на початку (дякую Луїсу Мендо).


2

Python 2 , 56 байт

-2 байти завдяки xnor. -3 байти завдяки ов.

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

Спробуйте в Інтернеті!

Буквально просто гольф псевдокод. : P


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

Тестові справи


Я переніс відповідь на retina @ MartinEnder, і це було лише 45 байт ...
Ніл


1

APL + WIN, 19 байт

Логіка схожа на рішення Дж. Галена.

(2|+⌿⌽<\⌽c∘.=c)/c←⎕     

1

Мова Вольфрама (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 = "".

Деякі Prologs трактують рядки в подвійних лапках як списки, SWI можна налаштувати так само, але для простоти я використовував гарне string_codes/2форматування виводу.



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(,"") читати вхід зі stdin.
  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="") друкувати вихід.

Причиною вашої помилки є те, що el()йде від methodsпакета, який, як правило, завантажується за замовчуванням, не TIO (обговорюється у моїй відповіді нижче)
duckmayr

чому ти використовуєш rev(unique(rev(y)))? Не буде просто unique(y)працювати? ooohhh чекаю, я бачу, ви хочете, щоб унікальні символи справа наліво. У цьому випадку unique(y,,T)(налаштування fromLast=T) буде 88 байт .
Джузеппе




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
}

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

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   */
}

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.

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.



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

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.




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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.