Tengo un algoritmo de aplanamiento de lista:

def flatten(s):
    if not s:
        return s
    if isinstance(s[0], (list, set, tuple)):
        return flatten(s[0]) + flatten(s[1:])
    return s[:1] + flatten(s[1:])

Pero no funciona si combina dos tipos de datos diferentes . Una lista dentro de una tupla, por ejemplo. ¿Hay alguna forma de hacer esto? ¿También sería posible aplastar los dictados? Los valores, no las claves.

1
user11771557 1 oct. 2019 a las 14:20

4 respuestas

La mejor respuesta

Las otras respuestas son todas válidas, pero si está importando sympy en su código, ¿tal vez use su método de aplanar? Es muy rápido y se adapta a tus necesidades.

1
Legorooj 2 oct. 2019 a las 23:17

Hay varios algoritmos en SO para aplanar listas anidadas y tuplas, pero nos quedaremos con las suyas. La primera observación es que su algoritmo tal como está escrito no funcionará con las instancias set ya que no son subscriptables. Entonces los sets tienen que irse:

def flatten(s):
    if not s:
        return s
    if isinstance(s[0], (list, tuple)):
        return list(flatten(s[0])) + list(flatten(s[1:]))
    return list(s[:1]) + list(flatten(s[1:]))

flatten([[1,2,(3,4,(5,6))]])

Huellas:

[1, 2, 3, 4, 5, 6]
3
Booboo 1 oct. 2019 a las 11:56

Si buscas optimización y algo de diversión ... La recursión es okey, pero no te olvides de RecursionError.

Entrada:

from datetime import datetime
from typing import Sequence


def timer(f):
    def wrapped(s):
        start = datetime.now()
        result = f(s)
        print(datetime.now() - start)
        return result
    return wrapped


@timer
def str_method(s: Sequence):
    return [int(x) for x in
            str(s).replace("(", "[").replace(")", "]")[1:-1].replace("[", "").replace("]", "")
            if x not in [",", " "]]


def flatten(s: Sequence):
    if not s:
        return s
    if isinstance(s[0], (list, tuple)):
        return list(flatten(s[0])) + list(flatten(s[1:]))
    return list(s[:1]) + list(flatten(s[1:]))

if __name__ == '__main__':
    s = [1, 2, (3, 4, (5, 6))]
    start = datetime.now()
    print(flatten(s))
    print(datetime.now() - start)
    print(str_method(s))
    print("-")
    s = [(x, ) for x in range(100)]
    start = datetime.now()
    flatten(s)
    print(datetime.now() - start)
    str_method(s)
    print("-")
    s = [(x, ) for x in range(100000)]
    start = datetime.now()
    try:
        print(flatten(s))
    except RecursionError:
        print("RecursionError")
    str_method(s)

Salida:

[1, 2, 3, 4, 5, 6]
0:00:00.000022 # flatten
0:00:00.000041 # str_method
[1, 2, 3, 4, 5, 6]
-
0:00:00.000369 # flatten
0:00:00.000122 # str_method
-
RecursionError # flatten
0:00:00.186894 # str_method
2
Artem Getmanskiy 1 oct. 2019 a las 12:49

Por lo general, se recomienda usar itertools -> cadenas o bibliotecas estándar, pero para contenedores anidados arbitrariamente:

xlen = len(x)
result = []    

def flatten(x, i, xlen, result):
  if i >= xlen:
    return
  if not isinstance(x[i], (list, set, tuple)):
    result.append(x[i])
  else:
    flatten(list(x[i]), 0, len(x[i]), result)
  flatten(x, i+1, xlen, result)

Puede agregar vitrinas para contenedores vacíos, etc.

4
Ketan 1 oct. 2019 a las 13:41
58183748