追加と消去


14

文字のみで構成される1行を指定して、次のように処理します。

  • 最初は空の文字列を維持します。
  • 次の入力文字が文字列にある場合は、文字列から削除します。
  • 次の入力文字が文字列にない場合は、文字列に追加します。

文字列の最終状態を出力します。

入力が少なくとも1文字(空でない)で構成されていると安全に想定できますが、出力が空でないという保証はありません。

擬似コード(これを自由にゴルフしてください):

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

回答:


10

Haskell44 42バイト

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

オンラインでお試しください! 編集:Zgarbのおかげで-2バイト!

説明:

2行目(#)は、文字列sと文字を受け取りx、削除または追加のいずれかを実行する関数を定義します。これはfilterxinのすべての出現を削除することで達成さsれ、文字列になりますz。場合xに発生していないs場合、zに等しいsz++[x|z==s]して、元の文字列を生成x添付。それ以外の場合[x|z==s]、空の文字列が生成され、フィルタリングされた文字列のみが返されます。

foldl(#)""は、文字列を取り、関数で最初に空の文字列""を次々に追加する匿名関数(#)です。


2
フィルターを再利用して42バイト
ズガルブ


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

~:&.|-反転してから、nubふるい(charは一意)を適用し、再度反転します。したがって、文字列内の文字の最後の出現を見つけます。

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

* -sringの文字の最後の位置のカウントに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

R92 84 77バイト

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

オンラインでお試しください!

djhurioのおかげで-15バイト

説明

djhurioは、forRプログラマーが本能的に原則として行うように、ループを回避する優れたR回答を提供しました(自分自身を含む)。forループを利用する(そしてプロセスで数バイトを節約する)Rの回答を次に示します。

  • x=scan(,''); -入力を変数に割り当てる x
  • y=''; -と呼ばれる変数に空の文字列を作成します y
  • for(i in el(strsplit(x,'')))-すべての文字のためiにありますx
  • y=c(y[y!=i],if(!i%in%y)i)- 等しくないyすべての要素に割り当て、まだ存在していない場合は追加yiiiy
  • cat(y,sep='')-要素のy間にスペースを入れずに印刷します

注意

上記のTIOリンクをクリックすると、ヘッダーに表示されlibrary(methods)ます。これは、関数に関して経験したdjhurioのエラーに対処するためel()です-関数はmethodsパッケージによって提供され、これは私が使用したRのどのバージョンでもデフォルトでロードされますが、何らかの理由でTIOによってではありません。場合はlibrary(methods)、ヘッダーから削除され、unlist置換されるel、私は4つのバイトを得るが、そうでしょう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

@djhurio-私は知っています、Rのforループが何かに役立つことはほとんどありません。あなたの提案について:素晴らしいアイデア!現在、この提案は回答に組み込まれています。
-duckmayr

1
@djhurio-結構です; 私は、elseステートメントを省略したことによってもたらされた違いを見るのに忙しすぎました。編集中。すごい仕事!
ダックマイヤー

1
@djhurio @duckmayrには、基本的にこのソリューションを採用し、文字を抽出するためにわずかに異なるアプローチを使用している73バイトのソリューションがあります。別の回答として投稿する気はありませんでした。また、ノート...[[1]]より長いel(...)よりも短いもののunlist(...)、その提供...の長さ1のリストである
ジュゼッペ

1
スクラッチ、文字であり、空の文字列に変換されるため、70バイトの回答を見つけました。0nul
ジュゼッペ

2

MATL、6バイト

vi"@X~

TIO環境では動作しませんが、MATLAB実装では正常に動作します。最新のパッチのおかげで、MATL Onlineで試すことができます。

X~等しいsetxor、または対称差。これは、チャレンジが求めることを正確に行います。残りは入力i"@をループし、最初は空のスタック全体を連結して空の文字列で開始します(Luis Mendoに感謝)。


2

Python 2バイト

xnorのおかげで-2バイト。ovsのおかげで-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:]
ovs


1

JavaScript(ES6)、60バイト

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

テストケース


私は@MartinEnderのRetina回答を移植しましたが、それはたった45バイトでした...-
ニール


1

APL + WIN、19バイト

GalenのJソリューションに似たロジック。

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

1

Wolfram言語(Mathematica)、36バイト

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

オンラインでお試しください!

入力と出力を文字のリストとして受け取ります。

使い方

//.(alias ReplaceRepeated)を使用して、繰り返される2つの文字を見つけ、繰り返される文字がなくなるまで両方を削除します。文字が2回以上出現する場合、Mathematicaは常に最初の2つの出現を削除します。そのため、キャラクターが奇数回出現した場合、その最後のインスタンスが常に生き残ります。


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 3番目の引数が最初の引数と統合され、2番目の引数のすべてのインスタンスが削除されます。
  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出力を適切にフォーマットしました。



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バイトのGiuseppeに感謝します!

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)か?ああ、待って、右から左にユニークなキャラクターが欲しい。その場合unique(y,,T)(設定fromLast=T)は88バイトになります
ジュゼッペ


0

APL(Dyalog)、16バイト

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

オンラインでお試しください!

エラーが許可された場合、これは9バイトになります。

(,⍨~∩)/∘⊖

エラーとはどういう意味ですか?
-FrownyFrog

@FrownyFrog 9バイトバージョンはDOMAIN ERROR、文字列が空の場合、(,⍨~∩)定義済みのID要素がないためスローされます。
エリックアウトゴルファー


0

ルビー、53バ​​イト

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

オンラインでお試しください!

入力と出力は両方とも文字の配列です。コードの呼び出し.charsをテストし.join、便宜上。

説明

結果の文字列の文字が奇数回、右から左の順に表示されるという事実を使用します。

->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バイト

{_xD_Qf%/QT2Q

入力を文字のリストとして取り込みます。試してみてください!

      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

ローダ、34バイト

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

オンラインでお試しください!

これは、擬似コードの直接変換です。入力と出力を文字のストリームとして扱います。

説明:

{                    /* 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 3、73バイト

最短ではありませんが、私はこのアプローチが好きです。

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

オンラインでお試しください!

文字列をループし、次の文字のみを保持します。

  • (s.count(c)%2) == 0 -文字が偶数回表示されます。
  • (i==s.rfind(c)) -現在のインデックスは、問題のキャラクターの最後の外観です。

0

REXX、102バイト

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

オンラインでお試しください!

仕組み:右端の文字を取得し、出現回数が偶数か奇数か(これも真理値として2倍になります)を確認し、奇数の場合は出力文字列に追加します。次に、入力文字列から文字のすべての出現を削除します。入力がなくなるまで繰り返します。



0

Java 8、93バイト

からStringまでのラムダString。質問の擬似コードの単なる実装。

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

オンラインで試す

Java 8、182バイト

ストリームを使用する同じタイプの別のラムダがあります!おそらくより効率的です。

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

オンラインで試す

非ゴルフ

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バイト

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

オンラインでお試しください!

djhurioからこのソリューションを投稿するように勧められました。djhurioの答えはここにあります

これはduckmayrの答えと同じ考え方を使用しますが、文字列を文字に分割するのではなくコードポイントに変換することで数値アプローチを活用し、完全なプログラムではなく関数なので、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
}

一つの重要な観察は、それがあるFに初期化されFALSEたり0utf8ToInt(0)==""、ので、これは空の文字列のための成功だけでなく、正しくコードポイントを崩壊します。




0

SNOBOL4(CSNOBOL4)97 95バイト

	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

オンラインでお試しください!

	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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.