¿Cómo se dividen los enteros dentro de una lista en solo dígitos?

Digamos que tengo algo como esto:

list(range(9:12)) 

Lo que me da una lista:

  [9,10,11] 

Sin embargo quiero que sea como:

  [9,1,0,1,1] 

¿Qué divide cada entero en un solo dígito? ¿Hay algún modo de lograr esto sin sacrificar demasiado el rendimiento? ¿O hay una forma de generar listas como estas en primer lugar?

Puede generar el resultado final de manera eficiente sin tener que crear una cadena intermedia grande o pequeña utilizando itertools.chain.from_iterable .

 In [18]: list(map(int, chain.from_iterable(map(str, range(9, 12))))) Out[18]: [9, 1, 0, 1, 1] 

 In [12]: %%timeit ...: list(map(int, chain.from_iterable(map(str, range(9, 20))))) ...: 100000 loops, best of 3: 8.19 µs per loop In [13]: %%timeit ...: [int(i) for i in ''.join(map(str, range(9, 20)))] ...: 100000 loops, best of 3: 9.15 µs per loop In [14]: %%timeit ...: [int(x) for i in range(9, 20) for x in str(i)] ...: 100000 loops, best of 3: 9.92 µs per loop 

Escala de tiempos con entrada. La versión de itertools también usa la memoria de manera eficiente, aunque es ligeramente más lenta que la versión str.join si se usa con la list(map(int, ...)) :

 In [15]: %%timeit ...: list(map(int, chain.from_iterable(map(str, range(9, 200))))) ...: 10000 loops, best of 3: 138 µs per loop In [16]: %%timeit ...: [int(i) for i in ''.join(map(str, range(9, 200)))] ...: 10000 loops, best of 3: 159 µs per loop In [17]: %%timeit ...: [int(x) for i in range(9, 200) for x in str(i)] ...: 10000 loops, best of 3: 182 µs per loop In [18]: %%timeit ...: list(map(int, ''.join(map(str, range(9, 200))))) ...: 10000 loops, best of 3: 130 µs per loop 

La forma más sencilla es,

 >>> [int(i) for i in range(9,12) for i in str(i)] [9, 1, 0, 1, 1] >>> 

Convierta los números enteros en cadenas, luego split() la cadena y vuelva a convertir los dígitos a ints.

 li = range(9,12) digitlist = [int(d) for number in li for d in str(number)] 

Salida:

 [9,1,0,1,1] 

He investigado cómo puedo hacer esto un poco más. La primera función que escribí fue naive_single_digits , que utiliza el enfoque str , con una lista de comprensión bastante eficiente.

 def naive_single_digits(l): return [int(c) for n in l for c in str(n)] 

Como puedes ver, este enfoque funciona:

 In [2]: naive_single_digits(range(9, 15)) Out[2]: [9, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4] 

Sin embargo, pensé que seguramente no sería necesario construir siempre un objeto str para cada elemento de la lista; todo lo que realmente necesitamos es una conversión básica a dígitos. Por pereza, copié esta función desde aquí . Lo he optimizado un poco especificándolo a base 10.

 def base10(n): if n == 0: return [0] digits = [] while n: digits.append(n % 10) n //= 10 return digits[::-1] 

Usando esto, hice

 def arithmetic_single_digits(l): return [i for n in l for i in base10(n)] 

que también se comporta correctamente:

 In [3]: arithmetic_single_digits(range(9, 15)) Out[3]: [9, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4] 

Ahora a tiempo. También he probado con otra respuesta (revelación completa: lo modifiqué un poco para que funcione en Python2, pero eso no debería haber afectado mucho el rendimiento)

 In [11]: %timeit -n 10 naive_single_digits(range(100000)) 10 loops, best of 3: 173 ms per loop In [10]: %timeit -n 10 list(map(int, itertools.chain(*map(str, range(100000))))) 10 loops, best of 3: 154 ms per loop In [12]: %timeit arithmetic_single_digits(range(100000)) 10 loops, best of 3: 93.3 ms per loop 

Como puede ver, arithmetic_single_digits es en realidad algo más rápido, aunque esto es a costa de más código y posiblemente menos claridad. He probado contra insumos ridículamente grandes, por lo que puede ver una diferencia en el rendimiento: en cualquier escala razonable, todas las respuestas aquí serán increíblemente rápidas. Tenga en cuenta que la aritmética de enteros de python probablemente sea relativamente lenta, ya que no utiliza un tipo de entero primitivo. Si esto se implementara en C, sospecharía que mi enfoque sería un poco más rápido.

Comparando esto con la respuesta de viblo, usando Python 3 (puro) (para mi vergüenza, no he instalado ipython para Python 3):

 print(timeit.timeit("digits(range(1, 100000))", number=10, globals=globals())) print(timeit.timeit("arithmetic_single_digits(range(1, 100000))", number=10, globals=globals())) 

Esto tiene la salida de:

 3.5284318959747907 0.806847038998967 

Mi enfoque es bastante más rápido, presumiblemente porque solo estoy usando aritmética de enteros.

Otra forma de escribir una solución aritmética. Comparado con la solución de Izaak van Dongens, esto no usa un ciclo de tiempo, pero calcula de antemano cuántas iteraciones necesita en la lista de comprensión / ciclo.

 import itertools, math def digits(ns): return list(itertools.chain.from_iterable( [ [ (abs(n) - (abs(n) // 10 **x)*10**x ) // 10**(x-1) for x in range(1+math.floor(math.log10(abs(n) if n!=0 else 1)), 0, -1)] for n in ns ] )) digits([-11,-10,-9,0,9,10,11]) 

Conviértelo en una cadena y luego vuelve a la lista 🙂

 lambda x: list(''.join(str(e) for e in x)) 

También se puede hacer con la función de mapa.

 a=range(9,12) res = [] b=[map(int, str(i)) for i in a] for i in b: res.extend(i) print(res) 

Así es como lo hice:

 ls = range(9,12) lsNew = [] length = len(ls) for i in range(length): item = ls[i] string = str(item) if len(string) > 1: split = list(string) lsNew = lsNew + split else: lsNew.append(item) ls = lsNew print(ls) 
 def breakall(L): if L == []: return [] elif L[0] < 10: return [L[0]] + breakall(L[1:]) else: return breakall([L[0]//10]) + [L[0] % 10] + breakall(L[1:]) print(breakall([9,10,12])) --> [9, 1, 0, 1, 2]