三項演算子の式を評価する


29

アルファベット上文法を考える{ 0 1 ? :}によって定義されるプロダクションルール

S→ 010 ?:秒┃ 1 ?:

sから生成された文字列が与えられると、それを?:右結合式(たとえば、a?B?X:Y:c?d:e?f:gmeans a?(B?X:Y):(c?d:(e?f:g)))の式として解析し、次のセマンティクスで評価します。

eval(0) = 0
eval(1) = 1
eval(0?a:b) = eval(b)
eval(1?a:b) = eval(a)

結果が0の場合、固定値を出力します。出力が1の場合、異なる固定値を出力します。回答で選択した出力値(0/ / 1またはFalse/ True)を指定します。

テストケース

0 -> 0
1 -> 1
0?0:1 -> 1
0?1:0 -> 0
1?0:1 -> 0
1?1:0 -> 1
0?1?0:1:1 -> 1
1?0?1:1:1 -> 1
1?0:1?0:1?1:1 -> 0
1?1?1:0?1?0:0:0:0 -> 1
1?0:1?0?1:1?1:0:1?1?1:1:1?0:1 -> 0
1?1?1:0?0?1:1:0?1:0:1?1?0?0:0:1?1:0:0?1?0:1:1?0:1 -> 1
0?0?1?0?0:1:0?0:0:0?0?1:1:1?0:1:0?0?0?1:0:0?1:1:1?1?0:1:1 -> 0

ルール

  • 文字列を一部のプログラミング言語のコードとして解釈して実行する言語組み込み機能(JavaScript / Perl / Ruby / Pythonなど)を使用することはできませんeval
  • つまり、実際にコードを解析して入力文字列を評価する必要はありません。同等の結果を達成し、前のルールに違反しないアプローチをとることができます。
  • プログラムはに対してチェックされますperl -le 'print eval<>'
  • 最短のコード(バイト単位)が優先されます。

文字列を根本的に変更した後、文字列を$ my_languageコードとして解釈するevalのような言語ビルトインを使用してはどうですか?
アダム

文字列を$ some_other_languageコードとして解釈するビルトインはどうですか?
メゴ

@Adámそれは許可されません、ごめんなさい。
リン

@Megoうーん、そこには些細な不正行為の機会があるので、そのようなビルトインをすべてカバーするようにルールを拡張しました。
リン

1
マーティンのテストケースを踏まえて、おそらくと文法を定義する方が簡単だろうS → T | T ? S : ST → 0 | 1関連性について話をする必要がなくなり、?
ピーターテイラー

回答:



17

網膜、23バイト

r-1=+`0\?.:|1\?(.):.
$1

オンラインでお試しください!(最初の行は、改行で区切られたテストスイートを有効にします。)

説明

実際には非常に簡単です。入力は、+リテラルのみを含む三項を繰り返し評価することにより結果に還元されます。これが右連想的に行われることを確認するために、右から左にr一致を探し(-1=)、最後に見つかった一致のみを置き換えます()。

正規表現自体は、一致して0\?.:それを削除するか(の後のものだけを残す:)、またはの1\?.:.後の値に置き換え?ます。


正規表現が右から始まる場合、1stの代わりにstマッチを処理してはいけません-1か?
リーキー修道女

@LeakyNun残念ながら、制限を適用する前にマッチを逆転させると思います。
マーティンエンダー

10

Haskell、106101100 90 83バイト

これは、パターンHaskellのパターンマッチング機能に大きく依存しています。まず最初に、文字列を反転して、最初に出現するb:a?x(通常はとして読み取られるx?a:b)だけを検索し、その値で置き換えることができるようにします。これにより、適切な結合性が自動的に提供されます。ここでは、x:xsパターンを使用します。これは、関数fが実行していることです。その後、基本的fには、1つの数値(0または1)が残るまで、出力に繰り返し適用します。

@ Lynn、12バイトありがとう!

f(b:':':a:'?':x:l)|x>'0'=a:l|1>0=b:l
f(x:l)=x:f l
f x=x
until((<2).length)f.reverse

8

Brainfuck、82 64 63バイト

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

出力は\xfffor 0および\x00for 1です。Brainfuckの実装では、開始セルの左側への移動を許可する必要があります。

これは本質的にxsotのPython answerと同じアプローチを使用しますが、分岐は最初の82バイトのサブミッションと比較してたぶん難しいでしょう:

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

(このソリューションでは、出力は\xfefor 0\xfffor 1であり、入力が改行で終了すると、より広い互換性が実現します。)

xsotのソリューションを分析するのが面倒な場合、アイデアは次のとおりです。左から右に進んでください。表示された場合1?、貪欲に破棄します。表示されている場合は0?、それと対応するの間のすべてを破棄します:?が2番目の文字として表示されない場合、ループを停止し、残りの文字列の最初の文字を出力します。

したがって、82バイトのソリューションは、実際にそのスキームをかなり厳密に反映しています。内側のループは0?、xsotの内側のループと同じように処理します。入力文字をチェックせずにメインループに入るように注意します。つまり、?メインループに入る前の最初の文字ではなく、メインループの最後で2番目の文字が1回だけであるかどうかを確認する必要があります。

63バイトのソリューションは、本質的に内側と外側のループを1つに結合します。これらのループ間の類似性を考えると、これは可能だと思われます。メインループのメモリレイアウトは次のように説明できます。

[s] d c

where [x]は現在のセルを意味しsます- まだループしていることを示すダミーのゼロ以外の値として始まり、入力文字(0または1)ですぐに上書きされます。d細胞は、我々は途中にある場合に(負)の深さを保持している0?それ以外の場合は、0cどちらかになるだろう?か、:改行またはEOFか。

とを更新sした後、それに応じて更新してポインタを調整することでケースcを処理します。そうでない場合は、次の反復での値として現在の値を使用します。0?dcd


7

Python 2、76 74 73 72バイト

a=`id`
for c in input()[::-1]:a=(c+a,a[ord(c)*7%9]+a[4:])[a>'?']
print a

を避けるため、文字列リテラルとして入力しますraw_

出力は0またはが1続き<built-in function id>ます。


1
ハハ、b langの答えを読んだところ、ほぼ同じ答えを投稿しようとしていました。追加の最適化を3>>int(c)
次に示します。– xsot

これがどのように機能するかを説明することに注意してください?本当に
すてきに

@WorldSEnder思い付くのは難しいが、一度見ると理解しやすいソリューションのタイプだと思います。他のソルバーと同様に、文字列を逆方向に実行し、右端の条件を繰り返し処理します。
ミッチシュワルツ

その`id`トリック…!よくやった:)
リン

5

Python 2、89バイト

s=input()
while'?'<=s[1:]:
 n=s<'1'
 while n:s=s[2:];n+=-(s[1]<'?')|1
 s=s[2:]
print s[0]

入力は文字列リテラルとして取得されます。


5

グライム34 31バイト

E=d|d\?E.E
e`\1|\1\?_.E|\0\?E._

プリント1truthy入力用と0falsyもののために。 オンラインでお試しください! 残念ながら、最後のテストケースではTIOのメモリが不足しています。

説明

右結合性は、本質的であることを意味しa?b:ca常にどちらかではない01、長く表現決して。そのような真実の表現に一致するパターンを再帰的に定義し、それに対して入力をチェックします。sがすべてチェックされている場合、すべて:が実際にa :であることをチェックする必要もありません。入力??sと:sの数が等しく、一部?がaとして誤って分類された:場合、対応:するものは一致せず、Grimeの一致しますエンジンはバックトラックします。

E=d|d\?E.E
E=                      Define nonterminal E (for "expression") as
  d|                     a digit, OR
    d                    a digit,
     \?                  a literal ?,
       E                 a match of E,
        .                any character (will match a :), and
         E               another match of E.
e`\1|\1\?_.E|\0\?E._
e`                      Match entire input against this pattern (truthy expression):
  \1|                    a literal 1, OR
     \1\?                a literal 1?,
         _               a recursive match of truthy expression,
          .              any character (will match a :), and
           E|            any expression, OR
             \0\?E._     the same, but with 0 in front, and _ and E swapped.

5

Haskell、79 71 70 62 60 56バイト

編集: 3バイトの@Zgarbと4バイトの@nimiに感謝します!

e(x:'?':r)|a:_:s<-e r=last$e s:[a:tail(e s)|x>'0']
e x=x

これは、「何らかの固定値」出力規則を多少乱用する再帰的なアプローチです。編集:タプルを取り除くことは8バイトを節約するだけでなく、より良い出力をもたらします:"0"または"1"

ゴルフされていないバージョン:

eval (x:'?':r1) = if x=='1' then (a, r3) else (b, r3)
    where (a,':':r2) = eval r1
          (b, r3)    = eval r2
eval (x:r) = (x,r)

どのように機能しますか?この関数は、式の暗黙のツリーをトラバース
eval

eval 1?0?0:1:0?1:0 -> eval 1?          :
                             eval 0?0:1 eval 0?1:0

そして、形式のタプルを返します(result, rest)
最初のパターンが(x:'?':r1)一致するxまで'1'r1します"0?0:1:0?1:0"。再帰的に適用evalr1て部分式を評価し、0?0:1を返します(0,":0?1:0")。これをパターンに一致さ(a,':':r2)せるa=0と、とが得られr2=0?1:0ます。また、この部分式は再帰的に評価されるため、b='0'およびr3=""です。かどうかをチェックしxている'1''0'とリターンのいずれか(a, r3)または(b, r3)


1
素敵なアプローチ!うx>'0'の代わりに働きますかx=='1'
-Zgarb

おかげで、私は文字を扱っている間、それを考えていませんでした。
ライコニ

1
私が考えるあなたにも置き換えることができます':'によって_
ズガルブ

はい、コードは単にの代わりに任意の区切り文字でも動作し:ます。再度、感謝します!
ライコニ

1
いいね!あなたは置き換えることができif .. then .. elselast$e s:[a:tail(e s)|x>'0']
nimi

3

JavaScript(ES6)、53バイト

f=s=>s[1]?f(s.replace(/0\?.:|1\?(.):.(?!\?)/,"$1")):s

戻り値0または1有効な入力のために、無効な入力に対してハングします。説明:JavaScriptでは文字列の反転が厄介であるため、最初の71バイトの試みは、?そうでなければ結合性を妨げる負の先読みを使用して機能しました。

f=s=>s[1]?f(s.replace(/(.)\?(.):(.)(?!\?)/,(_,a,b,c)=>+a?b:c)):s

これはやや長かったので、意思決定を正規表現に組み込むことで問題を改善できるかどうか疑問に思いました。判明したように、71バイトもかかったため、すぐに成功するわけではありませんでした。

f=s=>s[1]?f(s.replace(/0\?.:(.)(?!\?)|1\?(.):.(?!\?)/,"$1$2")):s

それから、私は0?0:0?1:連想性を気にすることなく、常に何もしないことを知りました。これにより、約25%節約できました。


上部のコードブロックがありませんf=。あなたのバイト数がそれを考慮しているかどうかはチェックしていません。
パトリックロバーツ

@PatrickRoberts割り当ての結果のみを表示するログからコピーするので、私はそれを永遠にやっています(もちろん、非再帰関数には十分です)。
ニール

あなたの代わりに出力のログ入力からコピーすることができ@Neil
ASCIIのみ

@MarsUltorログ入力にはプロンプトが含​​まれていますが、このプロンプトは忘れずに除外する必要があります。これは、非再帰関数にとっては厄介な余分なステップであるため、デフォルトで出力からコピーします。
ニール

3

Perl、32 + 1(-pフラグ)= 33バイト

彼の解決策は私のものよりも14バイト短いため、@ Mitch Swartchの功績 です!Mitchより1バイト長いソリューションを提案
してくれ@Neilにも感謝します。

s/.*\K(0\?..|1\?(.)..)/\2/&&redo

ニーズ-pフラグを、だけでなく、-M5.010または-E実行します。例えば ​​:

perl -pE 's/.*\K(0\?..|1\?(.)..)/\2/&&redo' <<< "0
0?0:1
0?1?0:1:1
1?0:1?0?1:1?1:0:1?1?1:1:1?0:1
0?0?1?0?0:1:0?0:0:0?0?1:1:1?0:1:0?0?0?1:0:0?1:1:1?1?0:1:1"

説明:これは、基本的にブロック削減a?b:c(なしは確かに終わりから始め?に従う)bまたはcのtruthnessに応じて、a文字列のみを含むようになるまで何度も繰り返しを、10


-あなたのスコアにはカウントしませんか?ふむ 興味深い...良い答えです!
MayorMonty

@MayorMonty 1ライナーの場合、コマンドラインで呼び出すことができます。perl -e '<code>'このため、追加pコストは1バイトのみperl -pe '<code>'です。
ニール

@Neil Ahh、それは理にかなっています
MayorMonty

実際には、文字列を逆にする必要はありません。aに対して負の先読みを行う?ことができますが、この方法で34バイトに減らすことができました。
ニール

ここでは32 + 1である:s/.*\K(1\?(.)..|0\?..)/\2/&&redo
ミッチ・シュワルツ

2

Python 3、93 69バイト

def f(s):z=s.pop;r=z(0);return s and':'<z(0)and(f(s),f(s))[r<'1']or r

入力が文字のリストとして文字列で、出力のいずれかです"0""1"

>>>f(list("0?0:1"))
<<<"1"

ゴルフされていないバージョン:

def parse(s):
    predicate = s.pop(0)
    if s and s.pop(0) == '?':
        left, right = parse(s), parse(s)
        if predicate == '0':
            return right
        return left
    return predicate

別の試みが、かなり多くのバイトで:

i=input()[::-1]
a=[i[0]]
for o,z in zip(i[1::2],i[2::2]):a+=[z]if o<'?' else[[a.pop(),a.pop()][z>'0']]
print(a[0])

あなたの答えは機能かもしれません-2行目を削除できます。
リン

これはテストケースに合格しないため、テストされていないことは明らかです。また、未使用のバージョンではランタイムエラーが発生します。あなたの基本的なアイデアは良いです。いくつかの調整を行うと、Python 2で68、Python 3で69が得られます。
Mitch Schwartz

1
答えを自分で編集するよりも(答えを見る前にこの種のアプローチを考えていなかったので)答えを出すよりも、答えがバギーである間、じっと待っているほうが理にかなっていると思います。ここに私が言及した68があり、def f(s):x=s.pop(0);return[]<s<s.pop(0)>'>'and(f(s),f(s))[x<'1']or xあなたとの編集距離が小さいPython 3にはがありdef f(s):z=s.pop;r=z(0);return s and':'<z(0)and(f(s),f(s))[r<'1']or rます。
ミッチシュワルツ

@MitchSchwartzに感謝します。左からではなく、右からかなり解析します
-WorldSEnder

1
そうでなければ、右ではなく左、~~~
WorldSEnder

1

SED、75 74 68(-rの場合は40 + 1)41

:
s,(.*)1\?(.):.,\1\2,
s,(.*)0\?.:,\1,
t

コメントで@MitchSchwartzのトリックを使用してこれを減らすことができますが(.*)、追加の置換用語を使用して追加する必要がある場合があります。
ニール

@ニール、あなたは正しいかもしれませんが、私はそれを機能させる方法を理解することはできません。
ライリー

コメントの書式設定は混乱を招く可能性があるため、チャットで作成しました。chat.stackexchange.com
Mitch Schwartz

@MitchSchwartz Heh、空白のラベルは機能しますか?しかし、私はあなたの\3代わりに\2。また、行を結合し;てgetにすることもできます:;s/(.*)(1\?(.):.|0\?.:)/\1\3/;t
ニール

@Neilだった\3ので、以前のバージョンを誤ってコピーしてしまった。セミコロンについて知っています。しかし、なんとセミコロンを使用したいのでしょうか。
ミッチシュワルツ

0

Bash + GNUユーティリティ、42

rev|sed -r ':
s/(.):.\?0|.:(.)\?1/\1\2/
t'

他のほとんどのパターンマッチング回答と同様のアイデア。

イデオネ


0ケースの最初の文字をキャプチャする必要はありません。5バイト節約できます。
ニール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.