Schowek funkcji: kopiowanie

17

To wyzwanie jest związane z niektórymi funkcjami języka MATL w ramach wydarzenia Język miesiąca miesiąca 2018 . Powiązane wyzwanie : Schowek funkcji: wklej .


Wprowadzenie

Mátl ma kilka schowków , w których można przechowywać wartości (kopia) do późniejszego pobrania (wklej). Niektóre schowki są automatyczne , co oznacza, że ​​kopiowanie jest uruchamiane automatycznie przez określone zdarzenia. To wyzwanie koncentruje się na jednym z automatycznych schowka, zwanym schowkiem wprowadzania funkcji lub po prostu schowkiem funkcji .

Ten schowek przechowuje dane wejściowe czterech ostatnich wywołań normalnych funkcji pobierania danych. Funkcje normalne są najczęstszym typem funkcji w MATL. Pobieranie danych oznacza, że ​​funkcja pobiera co najmniej jedno wejście (funkcje, które nie przyjmują żadnych danych wejściowych, nie są uwzględniane przez schowek funkcji).

Można to najlepiej wyjaśnić za pomocą następujących przykładów, które wykorzystują dwie normalne funkcje:

  • +, który wyrzuca dwie liczby ze stosu i wypycha ich sumę.
  • U, która wyskakuje o jedną liczbę i przesuwa jej kwadrat.

Przykład 1 :

3 2 + 6 + 12 4 U + +

daje wynik 39. Kod jest interpretowany w następujący sposób:

  • Literały liczbowe, takie jak 3lub 12wypychane na stos
  • Funkcje takie jak +wyskakiwanie danych wejściowych i wypychanie danych wyjściowych na stos.

Wywołania funkcji w porządku chronologicznym to:

  1. 3 2 + daje 5
  2. 5 6 + daje 11
  3. 4 U daje 16
  4. 12 16 + 28
  5. 11 28 +daje 39.

Schowek można wyświetlić jako listę czterech list. Każda wewnętrzna lista zawiera dane wejściowe do wywołania funkcji, najpierw najnowsze . W obrębie każdej wewnętrznej listy dane wejściowe są w oryginalnej kolejności .

Więc po uruchomieniu kodu zawartość schowka jest (w notacji Python):

[[11, 28], [12, 16], [4], [5, 6]]

Przykład 2 :

10 20 U 30 +

pozostawia liczby 10i 430na stosie. Stos jest wyświetlany od dołu do góry na końcu programu.

Wywołania funkcji to

  1. 20 U daje 400
  2. 400 30 + daje 430

Ponieważ były tylko dwa wywołania funkcji, niektóre wewnętrzne listy definiujące schowek będą puste . Zwróć też uwagę, w jaki sposób 10nie jest wykorzystywany jako dane wejściowe do żadnej funkcji.

Zatem zawartość schowka po uruchomieniu kodu to:

[[400, 30], [20], [], []]

Przykład 3 (nieprawidłowy):

10 20 + +

jest uważany za niepoprawny, ponieważ +brakuje danych wejściowych do drugiego (w MATL-u domyślnie wyzwalałoby to dane wejściowe użytkownika).

Wyzwanie

Dane wejściowe : ciąg S z literałami liczb +i Uoddzielony spacjami.

Wyjście : zawartość schowka Funkcja po ocenie ciąg S .

Wyjaśnienia:

  • Możesz użyć dowolnych dwóch spójnych symboli do przedstawienia tych funkcji, innych niż cyfry. Możesz także użyć dowolnego spójnego symbolu jako separatora zamiast spacji.
  • Uwzględnione zostaną tylko dwie wskazane funkcje.
  • Łańcuch wejściowy będzie zawierał co najmniej jeden literał liczbowy i co najmniej jedną funkcję.
  • Wszystkie liczby będą dodatnimi liczbami całkowitymi, prawdopodobnie z więcej niż jedną cyfrą.
  • Możliwe jest, że niektóre literały liczbowe nie są używane przez żadną funkcję, jak w przykładzie 2.
  • Gwarantujemy, że wprowadzony kod jest prawidłowym kodem, bez dodatkowych liczb. Tak więc ciąg jak w przykładzie 3 nigdy nie wystąpi.
  • Końcowe puste wewnętrzne listy w danych wyjściowych można pominąć. Tak więc wynik w przykładzie 2 może być[[400, 30], [20]]
  • Każdy rozsądny, jednoznaczny format wyjściowy jest dopuszczalny. Na przykład, ciąg z przecinkiem, jak wewnętrzna rozdzielacza i średnikiem jako zewnętrzną separatora: 400,30;20;;.

Dodatkowe zasady:

Przypadki testowe

Input
Output

3 2 + 6 + 12 4 U + +
[[11, 28], [12, 16], [4], [5, 6]]

15 3 4 + 2 U 8 + U +
[[7, 144], [12], [4, 8], [2]]

3 6 9 12 + + 10 8 U 6
[[8], [6, 21], [9, 12], []]

8 41 12 25 4 5 33 7 9 10 + + + + + + + +
[[41, 105], [12, 93], [25, 68], [4, 64]]

10 1 1 + U U U U U
[[65536], [256], [16], [4]]
Luis Mendo
źródło
Czy [[28, 11], [16, 12], [4], [6, 5]]dane wyjściowe są prawidłowe dla pierwszego przykładu?
ovs
@ovs Nie, dane wejściowe na każdej wewnętrznej liście muszą być w oryginalnej kolejności, czyli jak w wywołaniu funkcji
Luis Mendo
Hm, czy zniechęcamy się od rozwiązania tego w MATL? : P
Erik the Outgolfer
1
Czy to jest schowek M?
Giuseppe,
1
@Giussepe Dokładnie! Nie wspomniałem tutaj o tej nazwie, ponieważ nie używamy funkcji M. Zrobię to w wyzwaniu „wklej”
Luis Mendo

Odpowiedzi:

3

05AB1E , 20 bajtów

A"D¸ˆn‚DˆO"4ô‡.V¯R4£

Wypróbuj online!

-4 podziękowania dla Emigny (oraz -8 podziękowania dla niego za aktualizowanie mnie o zasadach).

  • U: a
  • +: b
Erik the Outgolfer
źródło
4
:( ... Dlaczego tak seRïõS?
Luis Mendo
@LuisMendo Ten wynik jest tak poważny. :(
Erik the Outgolfer
Daj nam kontynuować tę dyskusję w czacie .
Erik the Outgolfer
5

Bash , 43 bajty

sed s/+/rdnFPrp+/g\;s/U/p2^/g|dc|tac|sed 4q

Wypróbuj online!

Spowoduje to wydrukowanie schowka w następującym formacie, zwróć uwagę na użycie \ x0F jako separatora.

item_1\x0Fitem_2
item_3
.
.
item_m\x0Fitem_n

Kluczową ideą jest przekazanie tego do dc, języka opartego na stosie, tak aby wydrukować wymagane elementy stosu.

Dane wejściowe są przesyłane do sed, gdzie każdy +jest zamieniany na rdnFPrp+, który w dc wypisuje drugą liczbę na stosie, a następnie \ x0F, a następnie najwyższą liczbę przed wykonaniem dodawania. sed zastępuje również każdy Uz p2^wydrukować element góry stosu i kwadratu.

Pierwsze polecenie podstawienia szastępuje wszystko, co oznaczono flagą g lobal g, +s przy pomocy rdnFPrp+. W dc rzamienia dwa górne elementy stosu, dduplikuje górny element, ndrukuje go bez nowej linii, Fwypycha 15 na stos i Pdrukuje jako znak (który jest ogranicznikiem), rzamienia ponownie, pdrukuje element najwyższego stosu, a następnie+ wykonuje dodanie do dwóch górnych przedmiotów stosu.

Mamy inne polecenie, aw sed polecenia są oddzielone średnikami lub znakami nowej linii, z których wybrana jest pierwsza opcja. Po prostu posiadanie ;spowoduje, że bash zinterpretuje to jako koniec komendy sed, więc jest to poprzedzone znakiem \.

W ostatnim poleceniu podstawienia Ujest zastępowane globalnie przez p2^. W trybie DC pdrukuje i 2^podnosi do drugiej potęgi.

Wynik sed jest analizowany jako kod dc, drukując cały schowek.

Potok do dc sprawia, że ​​dc interpretuje to jako kod dc. Teraz najnowsze połączenia są na dole, a starsze na górze.

Ponieważ linie są w odwrotnej kolejności, do naprawy tego służy tac(odwrotny cat).

I wreszcie sed wybiera pierwsze 4 linie z tac.

Jest to krótszy sposób na zrobienie tego head -4. sed wykonuje polecenia do każdego wiersza wejścia pojedynczo. Jeśli nie ma żadnych poleceń, nic nie jest robione na wejściu i jest ono zwracane bez zmian. 4qkaże sedowi wykonać polecenie qw wierszu 4. Gdy sed przetwarza wiersz 4 wejścia, pierwsze trzy wejścia zostały już wydrukowane. Polecenie qzamyka program, więc wypisuje czwartą linię i kończy, wykonując w ten sposób odpowiednik head -4.

Kritixi Lithos
źródło
4

Python 2 , 126 bajtów

s=[0];b=[]
for c in input().split():k='U+'.find(c)+1;b=[s[k-1::-1]][:k]+b;s=[int([c,s[0]**2,sum(s[:2])][k])]+s[k:]
print b[:4]

Wypróbuj online!

ovs
źródło
4

Haskell , 113 109 bajtów

take 4.([]#).words
x:y:s#"+":r=(x+y:s#r)++[[y,x]]
x:s#"U":r=(x*x:s#r)++[[x]]
s#n:r=read n:s#r
_#_=[]
infix 4#

Pierwsza linia definiuje anonimową funkcję, która pobiera ciąg, np "3 2 + 6 + 12 4 U + +", i zwraca listę list wskazówki: [[11,28],[12,16],[4],[5,6]]. Wypróbuj online!

Laikoni
źródło
2

Czysty , 140 bajtów

import StdEnv,Text
k[a,b:n]["+":s]=k[a+b:n]s++[[b,a]]
k[a:n]["U":s]=k[a^2:n]s++[[a]]
k n[v:s]=k[toInt v:n]s
k _[]=[]
$s=k[](split" "s)%(0,3)

Wypróbuj online!

W klasycznym stylu Clean jest to rozwiązanie Haskell, z wyjątkiem około 50% dłuższego.

Obrzydliwe
źródło
2

JavaScript (ES6), 107 bajtów

Pobiera dane wejściowe jako listę składającą się z liczb całkowitych '+'i 'U'. Zwraca inną listę składającą się z liczb całkowitych, tablic 2 liczb całkowitych i '_'pustych miejsc.

a=>a.map(x=>s.push(+x?x:(c=[x>[a=s.pop(),r=a*a]?a:[r=s.pop(),(r+=a,a)],...c],r)),s=[c='___'])&&c.slice(0,4)

Wypróbuj online!

Skomentował

a =>                          // a[] = input array
  a.map(x =>                  // for each entry x in a[]:
    s.push(                   //   update the stack:
      +x ?                    //     if x is a positive integer:
        x                     //       push x onto the stack
      :                       //     else:
        ( c = [               //       update the clipboard:
            x > [             //         compare x with '['
              a = s.pop(),    //         a = first operand
              r = a * a       //         use a² as the default result
            ] ?               //         if x is 'U' (greater than '['):
              a               //           save the 1st operand in the clipboard
            :                 //         else:
              [ r = s.pop(),  //           r = 2nd operand
                (r += a, a)   //           add the 1st operand
              ],              //           save both operands in the clipboard
            ...c              //         append the previous clipboard entries
          ],                  //       end of clipboard update
          r                   //       push r onto the stack
        )                     //
    ),                        //     end of stack update
    s = [c = '___']           //   initialize the stack; start with c = '___'
  ) &&                        // end of map()
  c.slice(0, 4)               // return the last 4 entries of the clipboard
Arnauld
źródło
2

Idź, 305 303 295 bajtów

Usunięto 8 bajtów dzięki @ovs

func e(s string){b,v,w,x,r:=[][]int{{},{},{},{}},[]int{},0,0,0;for _,d:=range Split(s," "){if d=="+"{w,x,v=v[0],v[1],v[2:];r=w+x;b=append([][]int{[]int{x,w}},b...)}else if d=="U"{w,v=v[0],v[1:];r=w*w;b=append([][]int{[]int{w}},b...)}else{n,_:=Atoi(d);r=n};v=append([]int{r},v...)};Print(b[0:4])}

Wypróbuj online!

ollien
źródło
2

Oktawa , 206 bajtów

s=strsplit(input(''));m=t=[];for z=s
if(q=str2num(p=z{1}))t=[t q];else
if(p-43)m{end+1}=(k=t(end));t(end)=k^2;else
m{end+1}=(k=t(end-1:end));t(end-1:end)=[];t(end+1)=sum(k);end
end
end
m(1:end-4)=[];flip(m)

Wypróbuj online!

Gdyby tylko Octave miał popskładnię. mto schowek pamięci, tstos.

Sanchises
źródło
czy mógłbyś konstruować mi todwrotnie, dodając elementy z przodu, a nie do końca?
Giuseppe
178 bajtów przy użyciu strategii przedstawionej powyżej
Giuseppe
@Guiseppe Clever. Zawsze mam wrażenie, że dołączanie jest zazwyczaj krótsze niż dodawanie, ale w tym przypadku duża liczba „zakończeń” powinna mnie
zmusić do
1

Python 3 , 218 204 bajtów

-14 bajtów dzięki ovs

from collections import*
def f(s):
	a=deque(maxlen=4);z=a.appendleft;b=[];x=b.pop
	for i in s.split():
		if'+'==i:c=x(),x();z(c);r=sum(c)
		elif'U'==i:c=x();z(c);r=c*c
		else:r=int(i)
		b+=r,
	print([*a])

Wypróbuj online!

Draconis
źródło
1

Czerwony , 335 330 bajtów

func[s][b: copy[]foreach c split s" "[append b either c >"+"and(c <"U")[do c][c]]r: copy[]until[t: 0 until[not parse
b[to copy c[2 integer!"+"](insert/only r reduce[c/1 c/2]replace b c c/1 + c/2 t: 1)to end]]until[not parse b[to copy
c[integer!"U"](insert/only r to-block c/1 replace b c c/1 ** 2 t: 1)to end]]t = 0]take/part r 4]

Wypróbuj online!

Bardziej czytelny:

f: func[s] [
    s: split s " "
    b: copy []
    foreach c s [
        append b either (c > "+") and (c < "U")[do c] [c]
    ]
    r: copy []
    until [
        t: 0
        until [
            not parse b [to copy c[2 integer! "+"]
            (insert/only r reduce[c/1 c/2]
            replace b c c/1 + c/2
            t: 1)
            to end]
        ]
        until [
            not parse b [to copy c[integer! "U"]
            (insert/only r to-block c/1
            replace b c c/1 ** 2
            t: 1)
            to end]
        ]
        t = 0
    ]
    take/part r 4  
]
Galen Iwanow
źródło
1

R , 205 182 bajtów

function(P){S=F
M=list()
for(K in el(strsplit(P," "))){if(is.na(x<-strtoi(K))){if(K>1){M=c(m<-S[1],M)
S[1]=m^2}else{M=c(list(m<-S[2:1]),M)
S=c(sum(m),S[-2:0])}}else S=c(x,S)}
M[1:4]}

Wypróbuj online!

M jest schowkiem pamięci, P program iS stos.

Technicznie Sjest inicjowany jako wektor zawierający pojedyncze zero, ale ponieważ nigdy nie otrzymujemy nieprawidłowego wejścia, oszczędza mi to bajt S={}.

Giuseppe
źródło
1

C (gcc) , 264 bajty

Użyłem rekurencji, aby móc użyć stosu funkcji jako stosu danych: lista wejściowa jest przeglądana i wykonywane są operacje: wyniki są wyświetlane w odwrotnej kolejności, a wypychania stosu nie są wyświetlane.

Stos jest implementowany jako lista połączona. Oto jak to działa:

  • Bieżący węzeł jest skonfigurowany za pomocą [wskaźnik do wartości, wskaźnik do poprzedniego węzła]
  • Aby przekazać wartość, jest ona zapisywana, a funkcja jest ponownie wywoływana z bieżącym węzłem.
  • Aby wstawić wartość lub zmodyfikować wartość na górze stosu, wartość poprzedniego węzła jest modyfikowana, a funkcja jest wywoływana ponownie z poprzednim węzłem.

Pierwotnie użyłem struktury dla węzłów, ale przełączyłem się na czyste wskaźniki, aby zaoszczędzić miejsce. Ciekawą cechą tej połączonej listy jest to, że czyści się ona po zakończeniu rekurencji.

#define _ printf
f(char**s,int**p){int**w,v,*y[]={&v,p},m,n,t,z;w=y;z=1;return(*s?(**s-85?**s-43?(--z,t=14,v=atoi(*s)):(t=6,w=p[1],m=**w,**w+=n=**p):(t=0,w=p,**w*=m=**p),v=f(s+1,w),_(v<4?",[%d]\0,[%d,%d]\0"+t+!v:"",m,n),v+z):0);}g(char**s){_("[");f(s,0);_("]\n");}

Wypróbuj online!

ErikF
źródło