Re: Módulo para combinatoria
Chema Cortes
pych3m4 en gmail.com
Mie Ago 16 04:07:22 CEST 2006
El 8/08/06, Arnau Sanchez<arnau en ehas.org> escribió:
> Repasando el archivo de la lista me encontré con este hilo de abril pasado... me
> ha hecho gracia, porque precisamente hice ese algoritmo (el de buscar la
> solución de "Cifras") para practicar clases y recursividad cuando empecé con
> Python (así que no espereis ninguna maravilla). Ahí va por si le interesara a
> alguien (¿?)
Para ser de un ejercicio de iniciación está muy completo.
Si admites una sugerencia, yo habría derivado la clase StringInt del
tipo int. Te evitarías tener que andar transformando a entero antes de
operar. También se puede aprovechar mejor la "representación" con el
fomato "%r" en lugar del "%s". A parte de ésto, tenías una redundancia
ya que volvías a añadir los dos operandos a la lista en el método
"process_pair". A ver qué te parece esta reescritura, es algo más
rápido que el que tenías:
#!/usr/bin/python
# Solves a simple math game: given an arbitray list of numbers, and using
# the 4 basic rules (+, -, /, *) between them, find (or be close to) another
# given number. Spanish readers will probably know it for the old "Cifras y
# Letras" quiz show.
#
# Comments: arnau en ehas.org
# Standard Python modules
import sys, time
class StringInt(int):
def __new__(cls,n=0,base=10,_repr=None):
self=super(StringInt,cls).__new__(cls,n)
self._repr = _repr or str(n)
return self
def __add__(self, n):
return StringInt( super(StringInt,self).__add__(n),
_repr="(%r+%r)"%(self,n) )
def __mul__(self, n):
return StringInt( super(StringInt,self).__mul__(n),
_repr="(%r*%r)"%(self,n) )
def __div__(self, n):
return StringInt( super(StringInt,self).__div__(n),
_repr="(%r/%r)"%(self,n) )
def __sub__(self, n):
return StringInt( super(StringInt,self).__sub__(n),
_repr="(%r-%r)"%(self,n) )
def __repr__(self):
return self._repr
# Uncomment to use integers instead of StringInt objects
#StringInt = int
class SeekNumber:
def __init__(self, final, numbers):
self.final = final
self.numbers = [StringInt(x) for x in numbers if x>0]
self.nearest = StringInt(0)
def process_pair(self, a, b):
values = [a+b, a*b]
if a>b: values.append(a-b)
if a<b: values.append(b-a)
if a%b==0: values.append(a/b)
return values
def check_value(self, val):
if abs(self.final-val) < abs(self.final-self.nearest):
self.nearest = val
print "debug: %d = %r delta=%d" %(self.nearest, val,
abs(self.final-val))
return self.final==val
def process(self, numbers):
for num in numbers:
if self.check_value(num): return num
for i1,n1 in enumerate(numbers[:-1]):
for i2,n2 in enumerate(numbers[i1+1:]):
others = numbers[:]
del others[i1+i2+1]
del others[i1]
for num in self.process_pair(n1, n2):
if self.check_value(num):
return num
values=self.process([num] + others)
if values:
return values
def run(self):
retval = self.process(self.numbers)
return retval or self.nearest
def main():
args = sys.argv[1:]
if len(args) < 3:
print "usage: numbers.py n1 n2 [n3] [n4] ... [nN] final"
sys.exit(1)
final, numbers = int(args[-1]), [int(x) for x in args[:-1]]
sn = SeekNumber(final, numbers)
t0 = time.time()
res = sn.run()
elapsed = time.time() - t0
if int(res) == final:
print "found!! (%0.2f secs): %d = %r" %(elapsed, final, res)
else:
print "not found (%0.2f secs). best aprox: %d = %r" %(elapsed, res, res)
if __name__ == "__main__":
main()
Más información sobre la lista de distribución Python-es