La marmellata non si aggiunge così


16

sfondo

Gli atomi aritmetici di Jelly si vectorizzano automaticamente. Infatti, x + y è ben definita quando x ed y sono numeri o matrici irregolari dei numeri. Il codice sorgente di Jelly implementa questo comportamento usando un vettorizzatore generico, ma per questa sfida prenderemo in considerazione solo l'aggiunta di numeri interi e matrici di interi nidificati.

definizioni

Definisci la profondità di x come 0 se x è un numero intero, come 1 se è un array piano intero (possibilmente vuoto) e come n + 1 se contiene almeno un elemento di profondità n e nessun elemento di profondità k> n .

In questo modo, 1 ha profondità 0 , [] e [1] e [1, 1] hanno profondità 1 , [[], []] e [[1], [1]] e [[1]] e [1 , []] ha profondità 2 , [1, [1, [1]]] ha profondità 3 , ecc.

L'operazione x + y è definita come segue.

  1. Se x ed y hanno profondità 0 , restituire loro somma.

  2. Se x ed y hanno profondità uguali ma positivi, applicare ricorsivamente + a tutti gli articoli di x ed i corrispondenti elementi di y .

    Se x ed y hanno lunghezze diverse, aggiungere la coda della matrice più alla matrice di somme.

    Restituisce il risultato.

  3. Se la profondità di x è strettamente inferiore alla profondità di y , applica ricorsivamente + a x e tutti gli elementi di y e restituisce il risultato.

    Fai il contrario se la profondità di y è strettamente inferiore a quella di x .

Ad esempio, considera l'operazione [1, [2, 3], [4]] + [[[10, 20], [30], 40, 50], 60] .

  • La profondità dell'argomento sinistro è 2 , mentre la profondità dell'argomento destro è 3 , quindi calcoliamo [1, [2, 3], [4]] + [[10, 20], [30], 40, 50 ] e [1, [2, 3], [4]] + 60 .

    • [1, [2, 3], [4]] e [[10, 20], [30], 40, 50] hanno entrambi la profondità 2 , quindi calcoliamo 1 + [10, 20] , [2, 3] + [30] e [4] + 40 .

      • 1 + [10, 20] = [1 + 10, 1 + 20] = [11, 21]

      • [2, 3] + [30] = [2 + 30, 3] = [32, 3]

        Si noti che 3 rimane intatto, poiché non ha un elemento corrispondente.

      • [4] + 40 = [4 + 40] = [44]


      50 non ha un elemento corrispondente, in modo che il risultato è [[[11, 21], [32, 3], [44], 50]] .

    • [1, [2, 3], [4]] + 60 = [1 + 60, [2, 3] + 60, [4] + 60] = [61, [2 + 60, 3 + 60], [ 4 + 60]] , risultante in [61, [62, 63], [64]] .

  • Il risultato finale è [[[11, 21], [32, 3], [44], 50], [61, [62, 63], [64]]] .

Compito

Scrivi un programma o una funzione che accetta due numeri interi, due matrici nidificate di numeri interi o una loro combinazione come input e restituisce la loro somma, come definito sopra.

Se la tua lingua ha più tipi simili a array (elenchi, tuple, vettori, ecc.) Puoi scegliere uno qualsiasi di essi per la tua risposta. Il tipo restituito deve corrispondere al tipo di argomento.

Per evitare soluzioni noiose e imbattibili, se una lingua ha questa operazione esatta come integrata, non è possibile utilizzare quella lingua.

Sono ammessi tutti i built-in di tutte le altre lingue. Se la tua lingua preferita lo consente, puoi sovraccaricare e / o ridefinire l'aggiunta integrata.

Questo è , quindi vince il codice più breve in byte.

Casi test

0 + 0                           = 0
[-1, 0, -1] + [1]               = [0, 0, -1]
[] + [0]                        = [0]
[] + 0                          = []
[] + []                         = []
[[], 0] + []                    = [[], []]
[1, 2, 3] + 10                  = [11, 12, 13]
[1, 2, 3] + [10]                = [11, 2, 3]
[1, 2, 3] + [10, [20]]          = [[11, 12, 13], [21, 2, 3]]
[1, 2, 3, []] + [10, [20]]      = [11, [22], 3, []]
[1, [2, [3, [4]]]] + [10, [20]] = [[11, [21]], [[12, [22]], [13, [24]]]]

Per generare più casi di test, è possibile utilizzare questo programma Jelly .


Cosa succede se la nostra lingua non supporta array irregolari? Siamo autorizzati a ristrutturare l'input o dovremmo implementare array irregolari? O forse usi semplicemente una lingua diversa?
miglia

Cosa intendi con ristrutturazione dell'input ?
Dennis,

Nel pensare ulteriormente, mi rendo conto che non avrebbe funzionato per ristrutturare l'input, ma comunque riassumerò ciò che intendevo prima. Ho pensato di utilizzare un valore di riempimento per il pad, il che eliminerebbe un po 'di lavoro ma creerebbe anche un problema diverso (probabilmente diverso dalla domanda prevista), ma ora mi rendo conto che anche i casi di test includono numeri negativi.
miglia

Le matrici possono anche essere eterogenee, quindi i valori di riempimento non sarebbero sufficienti per renderle rettangolari. Come ultima risorsa, c'è sempre la possibilità di operare sulle stringhe, ma probabilmente è troppo complicato.
Dennis

3
Ehi, bel titolo! .. ora che Google mi ha aiutato a ottenerlo :-)
Luis Mendo,

Risposte:


3

Pyth, 42 byte

L?sIb0heSyM+b0M?qFyMJ,GH?yGgM.tJ0+GHgLFyDJ

Suite di test

Gli ultimi 4 byte eseguono semplicemente la funzione sull'input.

L?sIb0heSyM+b0M?qFyMJ,GH?yGgM.tJ0+GHgLFyDJ

L?sIb0heSyM+b0
                  Define y(b), a helper function to calculate the depth.
 ?                Ternary:
  sIb             If b is invariant under the s function, which is only the case
                  if s is an int.
     0            The depth is 0.
           +b0    Add a 0 on to b. This handles the edge case where b is [].
         yM       Map each to their depth
       eS         Take the max.
      h           Add one.

M?qFyMJ,GH?yGgM.tJ0+GHgLFyDJ
M                               Define g(G, H), which calculates the Jelly +.
 ?                              Ternary:
       ,GH                      Form [G, H].
      J                         Save it to J.
    yM                          Map each to its depth.
  qF                            Check if they are equal.
          ?yG                   If so, check if the depth is nonzero.
               .tJ0             If so, transpose J, pairing each element of each
                                argument with the corresponding element of the
                                other. Pad with zeroes.
             gM                 Map each to its Jelly +.
                   +GH          If the depths are zero, return the normal sum.
                         yDJ    If the depths are different, order J by depth.
                      gLF       Apply the function which left-maps the Jelly +
                                function to the two values. The first is
                                treated as a constant, while the second varies
                                over elements over the second values.

7

APL, 44 byte

{1=≡⍺⍵:⍺+⍵⋄=/∆←|≡¨⍺⍵:⊃∇¨/↓↑⍺⍵⋄</∆:⍺∘∇¨⍵⋄⍵∇⍺}

APL di + distribuisce anche su array, ma in modo abbastanza diverso da non poter essere realmente utilizzato. Tuttavia, esiste una funzione di profondità integrata ( ).

Spiegazione:

  • 1=≡⍺⍵:⍺+⍵: se le profondità di sono entrambe pari a zero (e quindi la profondità di ⍺ ⍵è 1), aggiungile.
  • ∆←|≡¨⍺⍵: Prendere l'assoluto della profondità di entrambi e e memorizzarli in . ( fornisce un valore negativo se non tutti gli elementi hanno la stessa profondità.)
  • =/∆: se hanno la stessa profondità:
    • ↓↑⍺⍵: riempie l'array più corto con zero per abbinare l'array più lungo
    • ⊃∇¨/: distribuisce la funzione su entrambi gli array
  • </∆: se la profondità di è inferiore a quella di :
    • ⍺∘∇¨⍵: rilegare e quindi mappare
  • ⍵∇⍺: se non altro (quindi è più profondo di ), scambia gli argomenti e riprova.

3
A volte penso di conoscere APL ok. Poi vedo un capolavoro come questo e mi rendo conto di conoscerlo a malapena.
Alex A.

I caratteri APL contano davvero come byte?
metalim,

@metalim APL ha pagine di codice legacy che precedono Unicode di alcuni decenni. In questi, ogni carattere è un singolo byte.
Dennis,

Quindi il tipo di codifica dovrebbe essere fornito con la soluzione. Solo IMO.
metalim,

@metalim Ho aggiunto un link.
Adám,

5

Mathematica, 122 byte

d=Depth
x_~f~y_/;d@x>d@y:=y~f~x
x_~f~y_/;d@x<d@y:=x~f~#&/@y
x_List~f~y_:=MapThread[f,{x,y}~PadRight~Automatic]
x_~f~y_=x+y

Definisce una funzione ricorsiva fche calcola la somma. Facendo uso del pattern matching di Mathematica, questa funzione è composta da quattro definizioni separate:

x_~f~y_/;d@x>d@y:=y~f~x

Se la profondità di xè maggiore di quella di y, scambia gli argomenti in modo che dobbiamo gestire la distribuzione solo in una direzione (cosa che possiamo fare, poiché l'addizione è commutativa).

x_~f~y_/;d@x<d@y:=x~f~#&/@y

Se la profondità di xè inferiore a quella di y, sostituire ogni valore #in ycon f[x,#], che si occupa della distribuzione per argomenti di profondità diversa.

x_List~f~y_:=MapThread[f,{x,y}~PadRight~Automatic]

Altrimenti, se un argomento è un elenco (il che implica che l'altro è anche un elenco, poiché sappiamo che hanno la stessa profondità), inseriamo entrambi gli argomenti in un elenco, PadRight[..., Automatic]riempirli della stessa lunghezza con (che semplicemente riempie un matrice irregolare con zeri per renderlo rettangolare), quindi utilizzare MapThreadper applicare falle coppie corrispondenti delle due liste.

E infine, il caso base:

x_~f~y_=x+y

Se nessuno degli altri pattern corrisponde, dobbiamo provare ad aggiungere due numeri, quindi lo facciamo e basta.


5

Haskell, 150 byte

data L=S Int|V{v::[L]}
d(V z)=1+maximum(d<$>S 0:z);d _=0
S x!S y=S$x+y
x!y|d x<d y=V$(x!)<$>v y|d x>d y=y!x|1<2=V$v x#v y
(x:a)#(y:b)=x!y:a#b;a#b=a++b

Spiegazione

La prima riga definisce un tipo di dati algebrico L, che è un Scalare (contenente un Int) o un Vettore (contenente un elenco di Ls, a cui si accede utilizzando un record getter v, che è una funzione parziale L → [L].)

La seconda riga definisce la funzione di profondità : la profondità di un Vettore è una più la sua profondità massima. Anticipo S 0ai valori nel vettore, in modo che depth [] == 1 + maximum [depth (S 0)] == 1. La profondità di "qualsiasi altra cosa" (uno scalare) è 0.

La terza riga definisce il caso base per !(la funzione di addizione): la somma degli scalari è semplicemente uno scalare.

La quinta riga definisce una variante zipWith (!)che seleziona gli elementi dall'elenco più lungo quando uno di essi è vuoto.

La quarta riga è divisa in tre casi:

x!y | d x<d y = V$(x!)<$>v y
    | d x>d y = y!x
    | True    = V$v x#v y
  • Se la profondità di xè strettamente inferiore alla profondità di y, mappare (x!)sugli elementi di y. (L'uso di vè garantito per essere valido, come d(y) ≥ 1.)

  • Se la profondità di xè strettamente maggiore, capovolgi gli argomenti e riavvia.

  • Se la loro profondità è uguale, comprimi gli argomenti con (!). (L'uso di vè garantito per essere valido, poiché il caso è d(x) = d(y) = 0stato gestito come caso base.)

Casi test

instance Show L where
  show (S x) = show x
  show (V x) = show x

lArg = V [S 1, V [S 2, V [S 3, V [S 4]]]]
rArg = V [S 10, V [S 20]]

Poi show (lArg ! rArg) == "[[11,[21]],[[12,[22]],[13,[24]]]]".


Ho appena risolto anche questo ^^ (avevo scambiato le righe con leggibilità, ma l'ho fatto nel modo sbagliato ...) importÈ perché Ideone ha un vecchio compilatore Haskell. Le versioni moderne di GHC messo <$>in Prelude, quindi non è necessario per l'importazione Control.Applicativedi usarlo in questi giorni.
Lynn,

Troppe modifiche contemporaneamente alle altre mie azioni: P E certo, ora sembra ok, ma trovo abbastanza strano che causi un errore di compilazione. Tutti i bit di corrispondenza dei pattern di una funzione devono essere consecutivi?
FryAmTheEggman,

Esatto.
Lynn,

Va bene, grazie per tutto il tuo aiuto :) "Un giorno imparerò questa lingua" - FryAmTheEggman 7 anni fa.
FryAmTheEggman,

4

Java, 802 794 754 746 byte

Ho deciso di accettare @ Dennis ♦ per la sfida di operare sulle stringhe "come ultima risorsa" perché probabilmente era "troppo complicato". Inoltre, nella lingua peggiore per giocare a golf.

Le matrici nell'input sono separate da virgola, racchiuse tra parentesi quadre e senza spazi bianchi.

Programma completo con funzioni integrate in una classe e con casi di test

import java.util.*;
List<String>p(String s){List r=new ArrayList<String>();String p="";int l=0;for(char c:s.substring(1,s.length()-1).toCharArray()){l+=c=='['?1:c==']'?-1:0;if(c==','&&l<1){r.add(p);p="";}else p+=c;}if(p!="")r.add(p);return r;}
int d(String s){int l=0;if(s.contains("[")){for(String c:p(s))l=d(c)>l?d(c):l;l++;}return l;}
String f(String x,String y){int i=0;String r="";if(d(x)<1&&d(y)<1)r+=Integer.valueOf(x)+Integer.valueOf(y);else{r="[";if(d(x)<d(y))for(String k:p(y))r+=(i++<1?"":",")+f(x,k);else if(d(x)>d(y))for(String k:p(x))r+=(i++<1?"":",")+f(k,y);else for(;i<p(x).size()||i<p(y).size();i++)r+=(i<1?"":",")+(i<p(x).size()&&i<p(y).size()?f(p(x).get(i),p(y).get(i)):i<p(x).size()?p(x).get(i):p(y).get(i));r+="]";}return r;}

Potrei porta questo per C ++ più tardi in quanto è l'altra lingua che conosco che non supporta gli array frastagliati, dato che io sono abbastanza sicuro che quasi certo che sarà più breve di questa risposta. Questa è stata principalmente una dimostrazione del concetto, ma qualsiasi consiglio sul golf sarebbe comunque apprezzato!

-31 byte da @ user902383 suggerendo di usare un foreach su un array di caratteri convertiti, e quindi ho salvato un po 'di più dal riordinare i blocchi if nella parte finale.


È impressionante.
Dennis,

Penso che se sostituisci i tuoi loop con foreach loop tramite char array ottenuto da string, potresti risparmiare parecchi byte.
user902383

1
Errr ... Java supporta array irregolari; Non sono sicuro di cosa tu voglia dire. Usa Object[], che contiene nidificati Object[]o Integer. O solo Elenco non generico.
Robert Fraser

4

Python 2.7, 261 209 202 198 191 185 197 181 byte

Soluzione banale di FGITW

EDIT: ovviamente @Dennis lo batte

Grazie a @LeakyNun per aver salvato 57 byte con suggerimenti sulle espressioni lambda e 2 byte tra parentesi non necessarie.

Grazie a @Adnan per 4 byte a causa del suggerimento di utilizzare al typeposto diisinstance

Grazie a @Lynn per 7 byte con -~emap

Grazie a @FryAmTheEggman per z>=[] invece ditype

+12 byte per convertire lambda in caso contrario e correggere un bug importante

-16 byte grazie a @Kevin Lau - non a Kenny

Provalo online

d=lambda z:z==[]or z>[]and-~max(map(d,z))
p=lambda x,y:p(y,x)if d(x)>d(y)else(x+y if d(x)<1 else[p(a,b)for a,b in zip(x,y)]+x[len(y):]+y[len(x):])if d(x)==d(y)else[p(a,x)for a in y]

Passare a Python 2.7 è ancora più breve e scriverez==[]or`z`>']'and ...
Lynn,

Inoltre, penso che la sostituzione max(d(a)+1for a in z)con -~max(d(a)for a in z)salva un byte (perché è possibile rimuovere lo spazio prima max). Che è quindi solo -~max(map(d,z)).
Lynn,

Il passaggio a Python 2 consente di risparmiare ancora di più in che si può cambiare [p(a,b)for a,b in zip(x,y)]in map(p,x,y). Puoi ancora farlo in 3 ma devi aggiungere una chiamata a list. Penso che potresti anche migliorare il suggerimento di Lynn z>=[]. Non correlato, dovresti anche essere in grado di scambiare l' typeordine di confronto per risparmiare uno spazio.
FryAmTheEggman,

Err, volevo dire or`z`>'[', ovviamente, ma non posso più cambiare il mio commento. Ma in effetti, z>[]è ancora più breve (il ==caso è già gestito)!
Lynn,

La mappa @FryAmTheEggman non funziona quando le liste hanno dimensioni diverse; zip troncata correttamente. Aggiornerò con l'elenco che controlla
Blue

3

Python 2, 145 136 byte

d=lambda t:t>{}and-~max(map(d,t+[0]))
s=lambda x,y:s(y,x)if d(y)<d(x)else map(s,(x,[x]*len(y))[d(x)<d(y)],y)if d(y)else(x or 0)+(y or 0)

Provalo su Ideone .

Come funziona

In Python 2, tutti i numeri interi sono inferiori a tutti i dizionari, ma tutti gli elenchi sono maggiori. d calcola ricorsivamente la profondità di t restituendo 0 per numeri interi o il massimo incrementato della profondità dei suoi elementi e 0 . t+[0]evita il caso speciale dell'elenco vuoto.

s ricorsivamente calcola la somma Gelatina di x ed y .

Se la profondità di y supera x 's, s(y,x)chiama s con argomenti scambiati, assicurandosi che d (x) ≤ d (y) .

Se y ha una profondità positiva, map(s,(x,[x]*len(y))[d(x)<d(y)],y)procedi come segue.

  • Se il x 's e y profondità s' corrispondono, eseguemap(s,x,y) , mappando s su tutti gli elementi di x e gli elementi corrispondenti di y .

    Nel caso di elenchi di diverse lunghezze, map passerà None come argomento sinistro o destro per gli elementi mancanti nell'elenco più breve.

  • Se la profondità di x è inferiore a quella di y , esegue la map(s,[x]*len(y),y)mappatura s (x, ·) su y .

Se y (e, quindi, x ) ha profondità 0 , (x or 0)+(y or 0)sostituisce gli argomenti falsi ( Nessuno o 0 ) con zero e restituisce la somma degli interi risultanti.


1

JavaScript (ES6), 152 byte

f=(a,b,g=a=>a.map?1+Math.max(0,...a.map(g)):0)=>g(a)<g(b)?f(b,a):g(b)<g(a)?a.map(e=>f(e,b)):g(a)?a.length<b.length?f(b,a):a.map((e,i)=>f(e,b[i]||0)):a+b
;t=(x,y,z)=>o.textContent+=`
${JSON.stringify(x)}
${JSON.stringify(y)}
${JSON.stringify(z)}
${JSON.stringify(f(x,y))}
`;`
0 + 0                           = 0
[-1, 0, -1] + [1]               = [0, 0, -1]
[] + [0]                        = [0]
[] + 0                          = []
[] + []                         = []
[[], 0] + []                    = [[], []]
[1, 2, 3] + 10                  = [11, 12, 13]
[1, 2, 3] + [10]                = [11, 2, 3]
[1, 2, 3] + [10, [20]]          = [[11, 12, 13], [21, 2, 3]]
[1, 2, 3, []] + [10, [20]]      = [11, [22], 3, []]
[1, [2, [3, [4]]]] + [10, [20]] = [[11, [21]], [[12, [22]], [13, [24]]]]`.slice(1).split`
`.map(l=>t(...l.split(/ [+=] /).map(a=>JSON.parse(a))));
<pre id=o></pre>


1

Ruby 2.3, 143 145 148 149 byte

Ruby ha tutte queste piccole stranezze nel modo in cui zipfunziona con matrici di diversa lunghezza e mapcon funzioni multi-argomento, rendendo questo abbastanza divertente giocare a golf.

f=->x,y{d=->a{-~(a.map(&d).max||0)rescue 0}
d[x]<d[y]?y.map{|e|f[x,e]}:d[x]>d[y]?x.map{|e|f[e,y]}:d[x]<1?x+(y||0):[*x.zip(y).map(&f),*y[x.size..-1]]}

È molto interessante-- non ho mai visto quell'errore prima per questa funzione. Ho ancora corretto alcune cose a causa di altri bug ora, ma a parte questo funziona per me (ma fallisce ancora su ideone). Penso che sia perché ideone funziona con 2.1 e ne ho 2.3, quindi forse 2.1 non può semplicemente avere mapuna funzione a due argomenti nel modo in cui l'ho impostato alla fine. Ecco una versione modificata per 2.1 che funziona che modifica la mapchiamata alla fine per funzionare. ideone.com/q1jqTA
Value Ink

1

Julia, 113 byte

~=endof;!t=0t!=0&&1+maximum(!,[t;0])
x::Array+y::Array=(!x,~x)>(!y,~y)?y+x:!x<!y?map(t->x+t,y):~x<~y?[x;0]+y:x.+y

Provalo online!

Come funziona

~=endof

crea un alias a 1 byte per endof , che restituisce la lunghezza di un array.

!t=0t!=0&&1+maximum(!,[t;0])

definisce una funzione di profondità. La profondità di t è zero se e solo se 0t == 0 . In caso contrario, t è un array e la sua profondità viene calcolata come massimo incrementato della profondità dei suoi elementi e 0 . [t;0]aggiunge uno 0 all'array t , evitando così la necessità di un caso speciale l'array vuoto.

La somma integrata + di Julia si comporta già come la somma di Jelly se uno (o entrambi) dei suoi argomenti è un numero intero. Tuttavia, la somma di due matrici ( + ) richiede matrici della stessa forma e persino la somma vettoriale ( . + ) Richiede matrici che possono essere trasmesse a una forma comune.

Ridefiniamo + per un paio di array via

x::Array+y::Array=(!x,~x)>(!y,~y)?y+x:!x<!y?map(t->x+t,y):~x<~y?[x;0]+y:x.+y

Ciò non influisce sulla definizione di + per argomenti intero / intero, array / intero o intero / array.

(!x,~x)>(!y,~y)confronta lexicographically le coppie di profondità e lunghezze sia x ed y . Se la profondità di x supera y , o se la loro profondità corrisponde e la lunghezza di x supera y , y+xchiama ricorsivamente + con argomenti scambiati.

Altrimenti, !x<!yverifica se la profondità di x è inferiore a quella di y . In tal caso, map(t->x+t,y)mappa x + · su y .

Se la profondità corrisponde, ~x<~yverifica se x è più corto di y . In tal caso, [x;0]+ychiama ricorsivamente + dopo aver aggiunto uno 0 all'argomento sinistro.

Infine, se sia la profondità che la lunghezza sono identiche, le x.+ymappe + su tutti gli elementi di x e gli elementi corrispondenti di y .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.