Queste liste sono uguali?


19

Come forse saprai, Python ha delle liste. Come forse non sapete, queste liste possono contenere se stesse.

a = []
a.append(a)

Python 2

Python 3

Questi sono fantastici e ci sono molte cose interessanti che puoi fare con loro, tuttavia non puoi confrontarli.

a = []
a.append(a)
b = []
b.append(b)
a == b

Python 2

Python 3

Compito

Il tuo compito è quello di scrivere una funzione in Python (o qualsiasi linguaggio in grado di gestire direttamente gli oggetti Python) che prenderà due elenchi che possono contenere se stessi e confrontarli.

Due liste sono uguali se hanno la stessa lunghezza e non esiste una sequenza di numeri tale che l'indicizzazione di entrambe le liste in base a quella sequenza si traduca in due oggetti che non sono uguali in questa definizione di uguale. Tutti gli oggetti non di elenco contenuti in un elenco saranno interi di Python per semplicità e dovrebbero essere confrontati con l'uguaglianza integrata di Python per gli interi.

Il tuo programma non dovrebbe fare affidamento sulla profondità di ricorsione di Python per determinare se un elenco è infinitamente profondo. Questo è:

def isInfinite(a,b):
 try:
  a==b
  return False
 except RunTimeError:
  return True

Non è un modo valido per determinare se due elenchi sono autoreferenziali.

Casi test

Presuppone che tu definisca una funzione equal

a = []
a.append(a)
b = []
b.append(b)
print(equal(a,b))

True

a = []
b = []
a.append(b)
b.append(a)
print(equal(a,b))

True

a = []
b = []
a.append(1)
a.append(b)
b.append(1)
b.append(a)
print(equal(a,b))

True

a = []
a.append(a)
b = [a]
print(equal(a,b))

True

a = []
b = []
c = []
a.append(b)
b.append(c)
c.append(a)
equal(a,b)

True

a=[1,[2]]
b=[1,[2,[1]]]
a[1].append(a)
b[1][1].append(b[1])

True

a = []
a.append(a)
b = [1]
b.append(a)
c = [1]
c.append([c])
print(equal(b,c))

False

a = []
b = []
a.append(1)
a.append(b)
b.append(a)
b.append(1)
print(equal(a,b))

False

a = []
b = []
a.append(a)
b.append(b)
b.append(b)
print f(a,b)

False

17
Come nota a margine per i potenziali elettori: si noti che in genere le sfide specifiche della lingua vengono ignorate tranne che in determinate circostanze (come compiti che sono interessanti solo in determinate lingue). IMO, questo è un meraviglioso esempio di sfida specifica per la lingua.
DJMcMayhem

@WheatWizard Non è esattamente abbastanza: anche gli elenchi nidificati devono avere le stesse lunghezze.
xnor

@WheatWizard In realtà puoi confrontarli. In Python, si ottiene un "limite di ricorsione limitato" solo se non sono uguali. tio.run/nexus/…
mbomb007

@ mbomb007 Questo perché Python per impostazione predefinita confronta i riferimenti. Se hai due oggetti identici con riferimenti diversi, fallisce, quindi la sfida.
Mago del grano,

2
Puoi estendere questa sfida a tutte le lingue in cui gli elenchi possono contenere se stessi?
CalculatorFeline

Risposte:


9

Python 2 , 94 byte

g=lambda c,*p:lambda a,b:c in p or all(map(g((id(a),id(b)),c,*p),a,b))if a>[]<b else a==b
g(0)

Provalo online!

Un miglioramento della soluzione molto intelligente di isaacg di memorizzare le idcoppie di liste in elaborazione e dichiararle uguali se lo stesso confronto arriva a un livello inferiore.

Il passaggio ricorsivo all(map(...,a,b))dice che ae bsono uguali se tutte le corrispondenti coppie di elementi in esse sono uguali. Funziona bene per rifiutare una lunghezza diseguale perché mapriempie l'elenco più corto con None, a differenza di zipquale tronca. Poiché nessuno degli elenchi effettivi contiene None, questi elenchi imbottiti verranno sempre rifiutati.


Qual è lo scopo del ,dopo il c?
Mago del grano,

Lo rende una tupla.
mbomb007,

a=[];a+=[a,1];b=[];b+=[b,2];f(a,b)trabocca lo stack e a=[1];b=[2];f(a,b);f(a,b)sembra un problema di riusabilità.
Anders Kaseorg,

@AndersKaseorg, vedo, mutare l'elenco chiedeva problemi. Penso che questo lo risolva.
xnor

1
@AndersKaseorg E vedo che hai scritto sostanzialmente la stessa soluzione funzione in funzione. C'è una soluzione di 95 byte, senza che: f=lambda a,b,p=[0]:p[0]in p[1:]or all(map(f,a,b,[[(id(a),id(b))]+p]*len(a)))if a>[]<b else a==b. Forse c'è un modo migliore di gestire map.
xnor

5

Python, 233 218 197 217 byte

d=id
def q(a,b,w):
 w[(d(a),d(b))]=0
 if d(a)==d(b):return 1
 if(a>[]and[]<b)-1:return a==b
 if len(a)!=len(b):return 0
 for x,y in zip(a,b):
  if((d(x),d(y))in w or q(x,y,w))-1:return 0
 return 1
lambda a,b:q(a,b,{})

La funzione anonima sull'ultima riga esegue la funzione desiderata.

Questo è ancora in fase di golf, volevo solo dimostrare che questo è possibile.

In sostanza, inseriamo una voce in w se stiamo lavorando su un determinato controllo. Due cose sono uguali se sono lo stesso oggetto, se non sono elenchi e sono uguali o se tutti i loro elementi sono uguali o su cui si sta lavorando.


Non puoi usare a>[]invece di i(a,list)?
mbomb007,

@ mbomb007 È stato scritto prima dell'aggiunta della regola "Tutto è liste o ints". Si aggiorna.
isaacg,

Puoi usare a>[]<belen(a)-len(b)
mbomb007 il

@ETHproductions Oh, il suo conteggio dei byte è sbagliato. Ecco perché
mbomb007,

Può d(a)==d(b)essere a is b? Ciò taglierebbe due usi di d.
xnor
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.