追加和删除


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)

输入可以以任何适用的方式给出,但必须将其视为字符串,并且对于输出也应相同。这个程序应该不会有错误退出。

每种语言中最短的程序将获胜!

额外(可选):请说明您的程序如何工作。谢谢。


这行可以是空的吗?
user202729

1
@ user202729不。我稍作更改(它不会使任何答案无效),因此输入永远不会为空。
iBug

1
那么,为什么您拒绝ais523的编辑建议(链接)呢?
user202729

Answers:


10

Haskell44 42字节

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

在线尝试! 编辑:-2字节感谢Zgarb!

说明:

第二行定义了一个函数(#),该函数需要一个字符串s和一个字符x并执行remove或append。这是通过filterxin的所有出现都排除在外s而产生的z。如果x未在中出现s,则z等于sz++[x|z==s]产生带有x附加内容的原始字符串。除此以外[x|z==s]产生空字符串,仅返回过滤后的字符串。

foldl(#)""是一个匿名函数,它接受一个柱和其它最初空字符串之后添加一个字符""与该功能(#)


2
通过重用过滤器获得42个字节
Zgarb


8

J21 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

#~-复制右边的参数left arg。次(〜反转args的位置)

]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个字节

多亏了布鲁斯·福尔特(Bruce Forte),他才尘埃落定。

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

在线尝试!

接受字符串列表。

对称差异令人讨厌...


++union使用此方法可节省2个字节。
与Orjan约翰森


2

R92 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程序员本能地(通常包括我自己)那样做。这是一个利用for循环的R答案(并在过程中节省了一些字节)。

  • x=scan(,''); -将输入分配给变量 x
  • y=''; -在名为的变量中创建一个空字符串 y
  • for(i in el(strsplit(x,'')))-为每个字符ix
  • y=c(y[y!=i],if(!i%in%y)i)-分配给不等于的y每个元素,如果还不存在则附加yiiiy
  • cat(y,sep='')-打印的元素y之间没有空格

注意

如果单击上方的TIO链接,则会在标题中找到library(methods);这是为了解决djhurioel()功能上遇到的错误-该功能由methods软件包提供,在我使用的任何R版本中,该软件包都是默认加载的,但无论出于何种原因,TIO都不会加载。如果library(methods)从标题中删除if 并将unlist其替换为el,我将获得四个字节,但djhurio也会如此,将我们的字节数分别设置为96 88和99。


好一个。没想到for循环会更短。您可以通过省略else语句来使其更短for(i in el(strsplit(scan(,y<-''),y)))y=c(y[y!=i],if(!i%in%y)i);cat(y,sep='')
djhurio '17

@djhurio-我知道,在R a for循环中对任何事情都无济于事几乎是不可能的。关于您的建议:好主意!该建议现已纳入答案。
duckmayr

1
@djhurio-足够公平; 我忙于查看省略else语句所带来的差异,但我看不到您如何改变开始。现在编辑。做得好!
duckmayr

1
@djhurio @duckmayr有一个73字节的解决方案,基本上是采用这种解决方案,并使用略有不同的方法来提取字符。我真的不喜欢将其作为单独的答案发布。还要注意,...[[1]]它比el(...)unlist(...),但比短,但要提供...长度1的列表
Giuseppe

1
从头开始,我找到了70个再见答案,因为这0nul字符,并转换为空字符串。
朱塞佩

2

MATL,6个字节

vi"@X~

在TIO环境中不起作用,但是在MATLAB实现上可以正常工作,而且由于有了新的补丁,您可以在MATL Online上尝试

X~等于setxor或对称差,这正是挑战所要求的。其余的只是循环输入,i"@并通过连接开始时为空的整个堆栈以空字符串开头(感谢Luis Mendo)。


2

Python 2,56个字节

-2个字节感谢xnor。-3个字节,感谢ovs。

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

在线尝试!

从字面上看只是伪代码。:P


1
Save 2 bytes: s=(s+c).replace(c,c[c in s:]).
xnor

@xnor That's some basic golfing executed very cleverly. Thanks!
totallyhuman

1
-1 byte : s=s.replace(c,'')+c[c in s:]
ovs

1
56 bytes using reduce
ovs

1

JavaScript (ES6), 60 bytes

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

Test cases


I ported @MartinEnder's Retina answer and it was only 45 bytes...
Neil


1

APL+WIN, 19 bytes

Logic similar to Galen's J solution.

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

1

Wolfram Language (Mathematica), 36 bytes

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

Try it online!

Takes input and output as a list of characters.

How it works

Uses //. (alias ReplaceRepeated) to find two repeated characters and delete both, until no more repeated characters exist. If the character occurs more than twice, Mathematica will always delete the first two occurrences. So if a character occurs an odd number of times, its last instance will always be the one to survive.


1

Prolog 81 byte

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

Non-obfuscated version:

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 ensures that its third argument unifies with its first argument, with all instances of second argument removed from it.
  2. If those turn out to be the same, we append the element (it wasn't removed).
  3. append/3 as per its name, appends an element to list.
  4. We recur on the elements of the input until we hit the [] (empty list), at which point the intermediate result will unify with desired result.

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

Some Prologs treat strings in double quotes as lists, SWI can be configured to do the same, but for the sake of simplicity, I used string_codes/2 to format output nicely.



1

R, 84 bytes

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

Try it online!

Another solution, but there are better R answers here.

R, 88 bytes

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

Try it online!

Thanks to Giuseppe for -7 bytes!

There is a shorter answer by duckmayr.

  1. scan(,"") read input from stdin.
  2. y<-el(strsplit(scan(,""),"")) split input by characters and save as y.
  3. z=table(y<-el(strsplit(scan(,""),""))) compute frequencies of each character and save resulting table as z;
  4. unique(y,,T) take unique characters from the right side.
  5. names(z[!z%%2]) select only even counts and extract names.
  6. setdiff(unique(y,,T),names(z[!z%%2])) remove characters with even count.
  7. cat(setdiff(unique(y,,T),names(z[!z%%2])),sep="") print the output.

The reason for your error is that el() comes from the methods package, which while typically loaded by default, is not by TIO (discussed in my answer below)
duckmayr

why are you using rev(unique(rev(y)))? Wouldn't just unique(y) work? ooohhh wait I see, you want the unique characters from right to left. In that case unique(y,,T) (setting fromLast=T) will be 88 bytes.
Giuseppe

0

Alice, 9 bytes

/X&@
\io/

Try it online!

Explanation

Basically a port of Erik's answer. Apart from a bit of IP redirection the code is really just:

i&Xo@

which does:

i   Read all input.
&X  Fold symmetric multiset difference over the input.
o   Output the result.
@   Terminate.



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

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.



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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.