python - lenguaje - Convierte la lista de entradas a un número?
python wikipedia (15)
Tengo una lista de enteros que me gustaría convertir a un número como:
numList = [1, 2, 3]
num = magic(numList)
print num, type(num)
>>> 123, <type ''int''>
¿Cuál es la mejor manera de implementar la función mágica ?
EDITAR
Encontré this , pero parece que tiene que haber una mejor manera.
Dos soluciones:
>>> nums = [1, 2, 3]
>>> magic = lambda nums: int(''''.join(str(i) for i in nums)) # Generator exp.
>>> magic(nums)
123
>>> magic = lambda nums: sum(digit * 10 ** (len(nums) - 1 - i) # Summation
... for i, digit in enumerate(nums))
>>> magic(nums)
123
En realidad, la solución orientada al map
sale a la luz en mi caja; definitivamente no debería usar la sum
para cosas que podrían ser números grandes:
import collections
import random
import timeit
import matplotlib.pyplot as pyplot
MICROSECONDS_PER_SECOND = 1E6
FUNS = []
def test_fun(fun):
FUNS.append(fun)
return fun
@test_fun
def with_map(nums):
return int(''''.join(map(str, nums)))
@test_fun
def with_interpolation(nums):
return int(''''.join(''%d'' % num for num in nums))
@test_fun
def with_genexp(nums):
return int(''''.join(str(num) for num in nums))
@test_fun
def with_sum(nums):
return sum(digit * 10 ** (len(nums) - 1 - i)
for i, digit in enumerate(nums))
@test_fun
def with_reduce(nums):
return int(reduce(lambda x, y: x + str(y), nums, ''''))
@test_fun
def with_builtins(nums):
return int(filter(str.isdigit, repr(nums)))
@test_fun
def with_accumulator(nums):
tot = 0
for num in nums:
tot *= 10
tot += num
return tot
def time_test(digit_count, test_count=10000):
"""
:return: Map from func name to (normalized) microseconds per pass.
"""
print ''Digit count:'', digit_count
nums = [random.randrange(1, 10) for i in xrange(digit_count)]
stmt = ''to_int(%r)'' % nums
result_by_method = {}
for fun in FUNS:
setup = ''from %s import %s as to_int'' % (__name__, fun.func_name)
t = timeit.Timer(stmt, setup)
per_pass = t.timeit(number=test_count) / test_count
per_pass *= MICROSECONDS_PER_SECOND
print ''%20s: %.2f usec/pass'' % (fun.func_name, per_pass)
result_by_method[fun.func_name] = per_pass
return result_by_method
if __name__ == ''__main__'':
pass_times_by_method = collections.defaultdict(list)
assert_results = [fun([1, 2, 3]) for fun in FUNS]
assert all(result == 123 for result in assert_results)
digit_counts = range(1, 100, 2)
for digit_count in digit_counts:
for method, result in time_test(digit_count).iteritems():
pass_times_by_method[method].append(result)
for method, pass_times in pass_times_by_method.iteritems():
pyplot.plot(digit_counts, pass_times, label=method)
pyplot.legend(loc=''upper left'')
pyplot.xlabel(''Number of Digits'')
pyplot.ylabel(''Microseconds'')
pyplot.show()
Encontré algunos ejemplos que no son compatibles con Python 3. Probé uno de @Triptych
s = filter(str.isdigit, repr(numList))
num = int(s)
en python 3 va a dar error
TypeError: int() argument must be a string, a bytes-like object or a number, not ''filter''
creo que la manera más simple y compatible sería
def magic(num_list):
return int("".join(map(str, num_list)))
Encontré este hilo al intentar convertir una lista al valor real de la int subyacente en términos de un puntero de estilo C, pero ninguna de las otras respuestas parece funcionar en este caso. Creo que la siguiente solución funciona según lo previsto y podría ser útil para otros aunque no responda necesariamente a la pregunta original.
def listToInt(x, reverseBytes=False):
if reverseBytes:
x = x[::-1]
return reduce(lambda x,y: x*256+y, x)
listToInt([1, 249]) == 505
listToInt([249, 1], True) == 505
El valor principal de esto es emular el comportamiento de convertir una matriz de bytes a otro tipo de datos, por ejemplo, uint16, que Python parece no poder hacer de forma nativa, en un sistema endian grande o pequeño.
Este método funciona en 2.x siempre que cada elemento de la lista tenga solo un dígito. Pero en realidad no deberías usar esto. Es horrible.
>>> magic = lambda l:int(`l`[1::3])
>>> magic([3,1,3,3,7])
31337
Esto parece bastante limpio, para mí.
def magic( aList, base=10 ):
n= 0
for d in aList:
n = base*n + d
return n
Esto puede ser útil
def digits_to_number(digits):
return reduce(lambda x,y : x+y, map(str,digits))
print digits_to_number([1,2,3,4,5])
Si está usando numpy (con import numpy as np
):
In [24]: x
Out[24]: array([1, 2, 3, 4, 5])
In [25]: np.dot(x, 10**np.arange(len(x)-1, -1, -1))
Out[25]: 12345
Solo para completar, aquí hay una variante que usa print()
(funciona en Python 2.6-3.x):
from __future__ import print_function
try: from cStringIO import StringIO
except ImportError:
from io import StringIO
def to_int(nums, _s = StringIO()):
print(*nums, sep='''', end='''', file=_s)
s = _s.getvalue()
_s.truncate(0)
return int(s)
Tiempo de rendimiento de diferentes soluciones
He medido el rendimiento de las funciones de @ cdleary . Los resultados son ligeramente diferentes.
Cada función probada con la lista de entrada generada por:
def randrange1_10(digit_count): # same as @cdleary
return [random.randrange(1, 10) for i in xrange(digit_count)]
Puede suministrar su propia función a través del argumento de línea de comandos --sequence-creator=yourmodule.yourfunction
(ver a continuación).
Las funciones más rápidas para un número dado de enteros en una lista ( len(nums) == digit_count
) son:
len(nums)
en 1..30def _accumulator(nums): tot = 0 for num in nums: tot *= 10 tot += num return tot
len(nums)
en 30..1000def _map(nums): return int(''''.join(map(str, nums))) def _imap(nums): return int(''''.join(imap(str, nums)))
|------------------------------+-------------------|
| Fitting polynom | Function |
|------------------------------+-------------------|
| 1.00 log2(N) + 1.25e-015 | N |
| 2.00 log2(N) + 5.31e-018 | N*N |
| 1.19 log2(N) + 1.116 | N*log2(N) |
| 1.37 log2(N) + 2.232 | N*log2(N)*log2(N) |
|------------------------------+-------------------|
| 1.21 log2(N) + 0.063 | _interpolation |
| 1.24 log2(N) - 0.610 | _genexp |
| 1.25 log2(N) - 0.968 | _imap |
| 1.30 log2(N) - 1.917 | _map |
Para graficar la primera figura, descargue cdleary.py
y make-figures.py
y ejecute ( numpy
y matplotlib
deben estar instalados para trazar):
$ python cdleary.py
O
$ python make-figures.py --sort-function=cdleary._map /
> --sort-function=cdleary._imap /
> --sort-function=cdleary._interpolation /
> --sort-function=cdleary._genexp --sort-function=cdleary._sum /
> --sort-function=cdleary._reduce --sort-function=cdleary._builtins /
> --sort-function=cdleary._accumulator /
> --sequence-creator=cdleary.randrange1_10 --maxn=1000
Un trazador de líneas sin necesidad de lanzar hacia y desde str
def magic(num):
return sum(e * 10**i for i, e in enumerate(num[::-1]))
Usando una expresión de generador:
def magic(numbers):
digits = ''''.join(str(n) for n in numbers)
return int(digits)
pseudo-código:
int magic(list nums) { int tot = 0 while (!nums.isEmpty()) { int digit = nums.takeFirst() tot *= 10 tot += digit } return tot }
si la lista contiene solo un número entero:
reduce(lambda x,y: x*10+y, list)
# Over-explaining a bit:
def magic(numList): # [1,2,3]
s = map(str, numList) # [''1'',''2'',''3'']
s = ''''.join(s) # ''123''
s = int(s) # 123
return s
# How I''d probably write it:
def magic(numList):
s = ''''.join(map(str, numList))
return int(s)
# As a one-liner
num = int(''''.join(map(str,numList)))
# Functionally:
s = reduce(lambda x,y: x+str(y), numList, '''')
num = int(s)
# Using some oft-forgotten built-ins:
s = filter(str.isdigit, repr(numList))
num = int(s)
def magic(number):
return int(''''.join(str(i) for i in number))
def magic(numbers):
return int(''''.join([ "%d"%x for x in numbers]))