Üçlü operatörlerin ifadesini değerlendirme


29

Alfabe üzerinde dilbilgisi düşünün { 0, 1, ?, :} tarafından tanımlanan üretim kuralına

s → 010 ?ler :ler ┃ 1 ?ler :ler

S ' den üretilen bir dize göz önüne alındığında , onu ?:doğru ilişkisel olan bir ifade olarak ayrıştırın (örneğin, a?B?X:Y:c?d:e?f:ganlamına gelir a?(B?X:Y):(c?d:(e?f:g))) ve aşağıdaki anlambilimsel ile değerlendirin:

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

Sonuç 0 ise , bir miktar sabit değer verir; çıktı 1 ise , farklı bir sabit değer çıktılayın. Cevabınız için seçtiğiniz çıktı değerlerini (örn. 0/ 1, Veya False/ True) belirtin .

Test durumları

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

kurallar

  • Dizeleri bazı programlama dillerinde kod olarak yorumlayan ve bunu çalıştıran (örneğin, JavaScript / Perl / Ruby / Python's gibi eval) dil yerleşiklerini kullanamazsınız .
  • Bununla birlikte, kodunuzun aslında girdi dizesini ayrıştırması ve sonra değerlendirmesi gerekmez. Herhangi bir yaklaşıma eşdeğer sonuçlar elde edersiniz ve önceki kuralı ihlal etmez.
  • Programınız karşı kontrol edilecek perl -le 'print eval<>'.
  • En kısa kod (bayt cinsinden) kazanır.

Dizeyi kökten değiştirdikten sonra dizeleri $ my_language kodu olarak yorumlayan eval benzeri dil yerleşiklerini kullanmaya ne dersiniz?
Adám

Dizeleri $ some_other_language kodu olarak yorumlayan yerleşiklere ne dersiniz ?
Mego

@ Adám Üzgünüz, bu izin verilmez.
Lynn

@Mego Hmm, orada önemsiz bir aldatma fırsatı var, bu yüzden bu tür bütün yerleşikleri kapsayacak şekilde kuralı genişlettim.
Lynn

1
Martin'in test olguların ışığında, belki o kadar dilbilgisi tanımlamak kolay olurdu S → T | T ? S : S, T → 0 | 1, çağrışımsal bahsetmek ihtiyacını ortadan kaldırarak?
Peter Taylor

Yanıtlar:



17

Retina , 23 bayt

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

Çevrimiçi deneyin! (İlk satır, satır besleme ayrılmış bir test takımı sağlar.)

açıklama

Aslında oldukça basit. Girdiler, art arda ( +) sadece değişmezleri içeren üçlüleri değerlendirerek sonuçlara indirgenir . Bunun doğru bir şekilde yapıldığından emin olmak için, sağdan sola ( r) eşleşmeleri ararız ve sadece bulduğumuz son eşleşmeyi ( -1=) değiştiririz.

Düzenli ifadenin kendisi ya eşleşir 0\?.:ve onu kaldırır (yalnızca sonraki öğeleri bırakarak :) veya 1\?.:.onu sonraki değerle değiştirir ?.


Eğer regex sağdan başlarsa o zaman 1st yerine st karşılaşmasını -1işlememelisiniz?
Sızdıran Rahibe,

@LeakyNun Maalesef, limiti uygulamadan önce eşleşmeleri tersine çevirdiğimi düşünüyorum.
Martin Ender

10

Haskell, 106 101 100 90 83 bayt

Bu, ağır bir şekilde Haskell'in desen eşleştirme yeteneklerine dayanır. Her şeyden önce, dizgiyi tersine çeviririz b:a?x( ilk önce (normalde okurdu x?a:b)) ve onu onun değeriyle değiştiririz. Bu otomatik olarak doğru ilişkilendirme sağlar . Burada x:xskalıptan faydalanıyoruz . Fonksiyonun fyaptığı budur. Daha sonra, temelde f, tek bir numara (0 veya 1) kalana kadar tekrar tekrar çıkışına uygulanır .

12 bayt için teşekkürler @ Lynn!

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 bayt

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

Çıktı \xffiçin 0ve \x00içindir 1. Beyin tıkanması uygulaması, başlangıç ​​hücresinin soluna gitmeye izin vermelidir.

Esasen bu kullanımları xsot Python ile aynı yaklaşım cevap ama dallanma muhtemelen zor benim ilk 82 bayt sunulması ile karşılaştırıldığında takip etmektir:

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

(Bu çözüm için çıktı \xfeiçindir 0ve \xffiçindir 1ve girdi yeni bir satırla sona erdiğinde daha geniş bir uyumluluk sağlanır.)

Xsot'un çözümünü analiz etmek için canınız sıkılmazsa, fikir şudur: Soldan sağa doğru ilerleyin. Eğer görürseniz 1?o zaman açgözlülükle atın. Görüyorsanız 0?, bununla karşılık gelen arasındaki her şeyi atın :. Ne zaman ?ikinci karakteri, durdurma döngü olarak görünür ve kalan dizenin birinci karakteri yazdırmaz.

Bu yüzden, 82 baytlık çözüm aslında bu planı oldukça yakından yansıtıyor. İç döngü 0?, tıpkı xsot'un iç halkası gibi kullanılır. Herhangi bir giriş karakterini kontrol etmeden ana döngüye girmek için biraz özen gösterilir; yani, ikinci karakterin ?ana döngünün sonunda sadece bir kez olup olmadığını ve aynı zamanda ana döngüye girmeden önce de başlangıçta olup olmadığını kontrol etmek istiyoruz .

63 baytlık çözelti, iç ve dış ilmekleri esas olarak birleştirir, ki bu ilmeklerin arasındaki benzerlik göz önüne alındığında mümkün olduğunu düşündüm. Ana döngüdeki bellek düzeni şöyle tanımlanabilir:

[s] d c

burada [x]mevcut hücre anlamına gelir - ssadece hala döngü olduğumuzu gösteren ve bir giriş karakteriyle (ya 0da 1) hemen üzerine yazıldığını gösteren, kukla olmayan sıfır değeri olarak başlar . dHücre bir orta içindedir durumunda (negatif) derinliğini tutan 0?aksi takdirde 0. cYa olacak ?ya :satır veya EOF veya.

Güncellemeden sonra sve duruma göre güncelleyerek ve işaretçiyi ayarlayarak durumu cele alıyoruz , aksi takdirde bir sonraki yinelemenin değeri olarak geçerli değeri kullanırız veya bittiysek dururuz.0?dcd


7

Python 2, 76 74 73 72 bayt

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

Önlemek için hazır bilgi dizesi olarak giriş ile raw_.

Çıkışı takip eder 0veya 1takip eder <built-in function id>.


1
Haha, sadece b lang cevabını okudum ve neredeyse aynı bir cevap göndermek üzereydim! İşte ek bir optimizasyon:3>>int(c)
xsot

Bunun nasıl çalıştığını açıklamak ister misiniz? Gerçekten çok temiz görünüyor
WorldSEnder

@WorldSEnder Bence bu ortaya çıkması zor olabilir, ancak bir kez gördüğünüzde anlaşılması kolay bir çözüm. İpten geriye doğru ilerler ve diğer çözücüler gibi, sürekli olarak en doğru koşullu işlemi gerçekleştirir.
Mitch Schwartz

Bu `id`numara…! Aferin :)
Lynn

5

Python 2, 89 bayt

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

Girdi, değişmez bir dize olarak alınır.


5

Grime , 34 31 bayt

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

Baskılar 1truthy girişler için ve 0falsy olanlar için. Çevrimiçi deneyin! Son test davası maalesef TIO’da hafızası tükeniyor.

açıklama

Sağ associativity esasen içinde olduğu anlamına gelir a?b:c, aHer zaman ya 0ya 1, daha uzun bir anlatım olmadı. Ben sadece özyinelemeli böyle bir truthy ifadesiyle eşleşen bir model tanımlayacağım ve buna karşı girişi kontrol edeceğim. Ayrıca , hepsi işaretli ise, hepsinin :gerçekten bir olduğunu kontrol etmek gereksizdir : Girişte eşit sayıda s ve s vardır ve bazıları yanlış olarak a olarak sınıflandırılırsa , karşılık gelen eşleşmez ve Grime'nin eşleşmesi başarısız olur. motor geri dönecek.:??:?::

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 bayt

Düzenleme: 3 bayt için @Zgarb'a ve 4 bayt için @nimi'ye teşekkürler!

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

Bu , "bazı sabit değerler" - çıkış kuralını biraz kötüye kullanan, yinelemeli bir yaklaşım . Düzenleme: Kutulardan kurtulmak sadece 8 byte tasarruf sağlamakla kalmaz, aynı zamanda daha iyi bir çıktı verir: "0"veya "1".

Ungolfed versiyonu:

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)

O nasıl çalışır? Fonksiyon ifadelerin örtülü ağaç boyunca ilerleyen
eval

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

ve formun bir demetini döndürür (result, rest).
İlk model (x:'?':r1)maçları xiçin '1've r1için "0?0:1:0?1:0". Yinelemeli uygulanması evaliçin r1değerlendirir alt ekspresyonunu 0?0:1ve döner (0,":0?1:0"). Bunu kalıpla eşleştirmek ve (a,':':r2)verir . Bu alt formül aynı zamanda yinelemeli olarak değerlendirilir ve . Olmadığını kontrol edin olduğunu veya ve dönüş ya ya .a=0r2=0?1:0b='0'r3=""x'1''0'(a, r3)(b, r3)


1
Güzel yaklaşım! x>'0'Yerine işe yarar mıydı x=='1'?
Zgarb

Teşekkürler, karakterlerle uğraşırken bunu düşünmedim.
Laikoni

1
Ben düşünüyorum da yerini alabilir ':'tarafından _.
Zgarb

Evet, kod o zaman bile sadece sınırlayıcılar için çalışır :. Tekrar teşekkürler!
Laikoni

1
Güzel! Sen yerini alabilir if .. then .. elseile last$e s:[a:tail(e s)|x>'0'].
nimi

3

JavaScript (ES6), 53 bayt

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

Döndürür 0veya 1geçerli giriş için; geçersiz giriş için kilitleniyor. Açıklama: JavaScript'te bir dizgeyi ters çevirmek çok zor olduğu için, ilk 71 baytlık denemem ?, ilişkisizliği bozabilecek olumsuz bir bakış açısı kullanarak çalıştı :

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

Bu biraz uzun sürdüğü için, karar vermeyi regexp'e dahil ederek sorunları iyileştirip geliştiremeyeceğimi merak ettim. Anlaşıldığı üzere, hemen hemen bir başarı değildi, çünkü 71 byte de aldı:

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

O zaman aklıma geldi 0?0:ve 0?1:her zaman işsizlik, birliktelik endişesi olmadan. Bu beni neredeyse% 25 kurtardı.


Üstteki kod bloğunuz eksik f=. Bayt sayınızın hesaba katıp katılmadığını kontrol etmedim.
Patrick Roberts

@PatrickRoberts Bunu sonsuza dek yapıyorum çünkü günlükten kopyaladım, ki bu sadece ödevin sonucunu gösterir (ki bu, elbette tekrarlanamayan fonksiyonlar için yeterli).
Neil

Yerine çıkışın günlük girişten kopyalayabilirsiniz @Neil
ASCII yalnızca

@MarsUltor Günlük girişi, dışlamayı hatırlamam gereken bilgi istemi içeriyor. Bu özyinelemeli olmayan işlevler için garip bir ek adımdır, bu yüzden varsayılan olarak çıktıdan kopyalarım.
Neil

3

Perl, 32 + 1 (-p bayrak) = 33 bayt

@Mitch Swartch'a tam kredi , çünkü çözümü benimkinden 14 byte kısaydı! Mitch'ten daha uzun bir 1 baytlık çözüm öneren @Neil'e
de teşekkürler .

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

İhtiyaç -pbayrağı yanı sıra -M5.010veya -Eçalıştırmak için. Örneğin :

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çıklamalar : Temel olarak bloklarını azaltır a?b:c(sonundan başlayarak emin hayır olmak ?içine aşağıdaki) bveya cbir truthness bağlı adize yalnızca içerdiği kadar, tekrar tekrar 1veya 0.


-Puanınız doğru sayılmaz mı ? Hrm. İlginç ... İyi cevap!
BaşkanMonty

@MayorMonty 1-liner için komut satırından bunu kullanarak çağırabilir, perl -e '<code>'böylece pyalnızca 1 bayt ekleyebilirsin perl -pe '<code>'.
Neil

@Neil Ahh, bu mantıklı
MayorMonty

Aslında dizgiyi ters çevirmek zorunda değilsiniz, sadece bir tane için negatif bakabilirsiniz ?, bunu bu şekilde 34 byte'a kesmeyi başardım.
Neil

İşte bir 32 + 1:s/.*\K(1\?(.)..|0\?..)/\2/&&redo
Mitch Schwartz,

2

Python 3, 93 69 bayt

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

Girdi karakter listesi olarak dizedir, çıktı "0"ya"1"

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

Ungolfed versiyonu:

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

Başka bir deneme, ancak oldukça fazla bayt ile:

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

Cevabınız bir fonksiyon olabilir - ikinci satırı kaldırabilirsiniz.
Lynn

Bu, test durumlarını geçmediği ve test edilmemiş versiyonun çalışma zamanı hatası verdiği için açıkça test edilmiştir. Temel fikrin olsa iyi. Bazı ayarlamalar ile Python 2'de 68 ve Python 3'te 69 elde ediyorum.
Mitch Schwartz

1
Size cevabı vermenin benim için düzenlemekten ziyade (cevabınızı görmeden önce bu tür bir yaklaşımı düşünmedim) ya da cevabınız taşınırken beklerken oturmaktan daha mantıklı olduğunu düşünüyorum. Bahsettiğim 68 işte def f(s):x=s.pop(0);return[]<s<s.pop(0)>'>'and(f(s),f(s))[x<'1']or x, Python 3 için kendinize küçük bir düzenleme mesafesi var def f(s):z=s.pop;r=z(0);return s and':'<z(0)and(f(s),f(s))[r<'1']or r.
Mitch Schwartz

Teşekkürler @MitchSchwartz, hemen hemen sağdan ayrışmak, sola değil, ele
geçmek

1
Diğer taraftan, sağ yerine sola, ~~~
WorldSEnder

1

SED, 75 74 68 (-r için 40 + 1) 41

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

Muhtemelen onun içinde MitchSchwartz en hilesi @ kullanarak bu aşağı kesebilir yorumun kullanmak gerekebilir ancak (.*)ve ekstra yedek kelimesini ekle.
Neil

@Neil, haklı olabilirsin, ama nasıl çalışacağını çözemiyorum.
Riley,

Sohbette yazdım, çünkü bir yorumda biçimlendirme kafa karıştırıcı olabilir: chat.stackexchange.com/transcript/message/31709640#31709640
Mitch Schwartz

@ MitchellSchwartz Heh, boş etiketler işe yarıyor mu? Ama bence \3yerine demek istedin \2. Ayrıca, ;almak için çizgilere katılabilirsiniz :;s/(.*)(1\?(.):.|0\?.:)/\1\3/;t.
Neil

@Neil Ben bu \3yüzden önceki bir sürümü yanlışlıkla kopyaladım anlamına gelir. Noktalı virgülleri biliyorum. Ama yuck, neden noktalı virgül kullanmak istersiniz?
Mitch Schwartz,

0

Bash + GNU yardımcı programları, 42

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

Diğer kalıp eşleştirme cevaplarının çoğuna benzer bir fikir.

Ideone .


Bu 0durumda ilk karakteri yakalamanıza gerek yok , bu size 5 bayt kazandırır.
Neil
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.