Faire une liste plate à partir d'une liste de listes en Python

je me demande s'il y a un raccourci pour faire une liste simple à partir de la liste des listes en Python.

je peux faire ça en boucle, mais peut-être qu'il y a un "one-liner"cool? Je l'ai essayé avec réduire , mais je reçois une erreur.

Code

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)

message d'erreur

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
2195
demandé sur dreftymac 2009-06-05 00:30:05

30 réponses

flat_list = [item for sublist in l for item in sublist]

qui signifie:

for sublist in l:
    for item in sublist:
        flat_list.append(item)

est plus rapide que les raccourcis affichés jusqu'à présent. ( l est la liste pour les aplatir.)

Voici la fonction correspondante:

flatten = lambda l: [item for sublist in l for item in sublist]

pour preuve, comme toujours, vous pouvez utiliser le module timeit dans la bibliothèque standard:

$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop

Explication: les raccourcis basés sur + (y compris l'utilisation implicite dans sum ) sont, par nécessité, O(L**2) lorsqu'il y a des sous-listes L -- comme la liste des résultats intermédiaires s'allonge, à chaque étape un nouvel objet de la liste des résultats intermédiaires est attribué, et tous les éléments du résultat intermédiaire précédent doivent être copiés (ainsi que quelques nouveaux ajoutés à la fin). Ainsi (pour la simplicité et sans perte réelle de la généralité) dites que vous avez L sous-listes de I articles chacun: le premier I articles sont copiés d'avant en arrière L-1 fois, le second I articles L-2 nombre de fois, et ainsi de suite; le nombre total de copies est I fois la somme de x pour x de 1 à L exclu, i.e., I * (L**2)/2 .

la compréhension de la liste ne génère qu'une seule liste, une fois, et copie chaque élément (de son lieu de résidence original à la liste de résultats) aussi exactement une fois.

3158
répondu Alex Martelli 2017-06-14 21:53:08

vous pouvez utiliser itertools.chain() :

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

ou, sur Python >=2.6, utilisez itertools.chain.from_iterable() qui ne nécessite pas de déballage de la liste:

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))

cette approche est sans doute plus lisible que [item for sublist in l for item in sublist] et semble aussi plus rapide:

[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
10000 loops, best of 3: 24.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 45.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 488 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 522 usec per loop
[me@home]$ python --version
Python 2.7.3
1129
répondu Shawn Chin 2013-03-12 17:15:50

Note de l'auteur : c'est inefficace. Mais amusant, parce que les monades sont géniales. Ce n'est pas approprié pour la production de code Python.

>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

cela résume juste les éléments itérables passés dans le premier argument, en traitant le deuxième argument comme la valeur initiale de la somme (si elle n'est pas donnée, 0 est utilisé à la place et ce cas vous donnera une erreur).

parce que vous sommez des listes imbriquées, vous en fait obtenir [1,3]+[2,4] à la suite de sum([[1,3],[2,4]],[]) , qui est égal à [1,3,2,4] .

Remarque qui ne fonctionne que sur des listes de listes. Pour les listes de listes de listes, vous aurez besoin d'une autre solution.

656
répondu Triptych 2018-01-09 16:25:42

j'ai testé la plupart des solutions suggérées avec perfplot (un projet de la mine pet, essentiellement une enveloppe autour de timeit ), et a trouvé

list(itertools.chain.from_iterable(a))

être la solution la plus rapide (si plus de 10 listes sont concaténés).

enter image description here


Code pour reproduire le tracé:

import functools
import itertools
import numpy
import operator
import perfplot


def forfor(a):
    return [item for sublist in a for item in sublist]


def sum_brackets(a):
    return sum(a, [])


def functools_reduce(a):
    return functools.reduce(operator.concat, a)


def itertools_chain(a):
    return list(itertools.chain.from_iterable(a))


def numpy_flat(a):
    return list(numpy.array(a).flat)


def numpy_concatenate(a):
    return list(numpy.concatenate(a))


perfplot.show(
    setup=lambda n: [list(range(10))] * n,
    kernels=[
        forfor, sum_brackets, functools_reduce, itertools_chain, numpy_flat,
        numpy_concatenate
        ],
    n_range=[2**k for k in range(16)],
    logx=True,
    logy=True,
    xlabel='num lists'
    )
164
répondu Nico Schlömer 2018-06-18 11:05:28
from functools import reduce #python 3

>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

la méthode extend() dans votre exemple modifie x au lieu de retourner une valeur utile (ce que reduce() attend).

une façon plus rapide de faire la version reduce serait

>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
109
répondu Greg Hewgill 2018-01-02 05:02:41

Voici une approche générale qui s'applique aux numéros , chaînes de caractères , imbriqués listes et contenants" mixtes .

Code

from collections import Iterable


def flatten(items):
    """Yield items from any nested iterable; see Reference."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for sub_x in flatten(x):
                yield sub_x
        else:
            yield x

Note: en Python 3, yield from flatten(x) peut remplacer for sub_x in flatten(x): yield sub_x

Démo

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(flatten(lst))                                         # nested lists
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

mixed = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"]              # numbers, strs, nested & mixed
list(flatten(mixed))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']

Référence

  • cette solution est modifiée à partir d'une recette de Beazley, D. et B. Jones. Recette 4.14, Python Cookbook 3ème Ed., O'Reilly Media Inc. Sebastopol, CA: 2013.
  • trouvé un précédent so post , peut-être la démonstration originale.
62
répondu pylang 2018-07-26 17:00:44

je retire ma déclaration. la somme n'est pas le gagnant. Bien que ce soit plus rapide quand la liste est petite. Mais la performance se dégrade de manière significative avec des listes plus larges.

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
    ).timeit(100)
2.0440959930419922

la version de sum est toujours en cours d'exécution depuis plus d'une minute et elle n'a pas encore été traitée!

pour les listes de milieu:

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
20.126545906066895
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
22.242258071899414
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
16.449732065200806

en utilisant de petites listes et timeit: nombre=1000000

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
2.4598159790039062
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.5289170742034912
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.0598428249359131
32
répondu Nadia Alramli 2013-12-23 09:14:58

Pourquoi utiliser extend?

reduce(lambda x, y: x+y, l)

ça devrait marcher.

27
répondu Andrea Ambu 2014-12-31 12:07:09

il semble y avoir une confusion avec operator.add ! Lorsque vous ajoutez deux listes ensemble, le terme correct pour cela est concat , pas add. operator.concat est ce que vous devez utiliser.

si vous pensez fonctionnel, c'est aussi simple que cela::

>>> list2d = ((1, 2, 3), (4, 5, 6), (7,), (8, 9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)

vous voyez reduce respecte le type de séquence, donc quand vous fournissez un tuple, vous obtenez en retour un tuple. essayons une liste:

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Aha, vous obtenez une liste.

Comment parler de la performance::

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> %timeit list(itertools.chain.from_iterable(list2d))
1000000 loops, best of 3: 1.36 µs per loop

de_iterable est assez rapide! Mais ce n'est pas une comparaison à réduire avec concat.

>>> list2d = ((1, 2, 3),(4, 5, 6), (7,), (8, 9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop
21
répondu Meitham 2018-09-30 21:28:25

si vous voulez aplatir une structure de données où vous ne savez pas à quelle profondeur elle est imbriquée, vous pouvez utiliser iteration_utilities.deepflatten 1

>>> from iteration_utilities import deepflatten

>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(deepflatten(l, depth=1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> l = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]]
>>> list(deepflatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

c'est un générateur donc vous devez mouler le résultat à un list ou itérer explicitement sur elle.


pour aplatir un seul niveau et si chacun des éléments est lui-même itérable, vous pouvez également utiliser iteration_utilities.flatten qui lui-même est juste un emballage mince autour itertools.chain.from_iterable :

>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

juste pour ajouter quelques timings (basé sur la réponse de Nico Schlömer qui n'a pas inclus la fonction présentée dans cette réponse):

enter image description here

c'est un graphe log-log pour accommoder l'énorme gamme de valeurs portées. Pour qualitatifs raisonnement: Bas, c'est mieux.

les résultats montrent que si le itérable ne contient que quelques itérables internes alors sum sera le plus rapide, cependant pour les itérables longs seuls les itertools.chain.from_iterable , iteration_utilities.deepflatten ou la compréhension emboîtée ont une performance raisonnable avec itertools.chain.from_iterable étant le plus rapide (comme déjà remarqué par Nico Schlömer).

from itertools import chain
from functools import reduce
from collections import Iterable  # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten

def nested_list_comprehension(lsts):
    return [item for sublist in lsts for item in sublist]

def itertools_chain_from_iterable(lsts):
    return list(chain.from_iterable(lsts))

def pythons_sum(lsts):
    return sum(lsts, [])

def reduce_add(lsts):
    return reduce(lambda x, y: x + y, lsts)

def pylangs_flatten(lsts):
    return list(flatten(lsts))

def flatten(items):
    """Yield items from any nested iterable; see REF."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            yield from flatten(x)
        else:
            yield x

def reduce_concat(lsts):
    return reduce(operator.concat, lsts)

def iteration_utilities_deepflatten(lsts):
    return list(deepflatten(lsts, depth=1))


from simple_benchmark import benchmark

b = benchmark(
    [nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
     pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
    arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
    argument_name='number of inner lists'
)

b.plot()

1 avertissement: je suis l'auteur de cette bibliothèque

20
répondu MSeifert 2018-04-18 21:27:43

envisagez d'installer le paquet more_itertools .

> pip install more_itertools

il est livré avec une mise en œuvre pour flatten ( source , des recettes itertools ):

import more_itertools


lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.flatten(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

à partir de la version 2.4, Vous pouvez aplatir des itérables imbriqués plus compliqués avec more_itertools.collapse ( source , contribution d'abarnet).

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst)) 
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9]              # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
15
répondu pylang 2018-07-13 21:06:00

la raison pour laquelle votre fonction n'a pas fonctionné: l'extension étend le tableau en place et ne le renvoie pas. Vous pouvez toujours retourner x de lambda, en utilisant un truc:

reduce(lambda x,y: x.extend(y) or x, l)

Note: extend est plus efficace que + sur les listes.

13
répondu Igor Krivokon 2009-06-04 20:47:13

une mauvaise caractéristique de la fonction Anil ci-dessus est qu'elle exige de l'utilisateur de toujours spécifier manuellement le deuxième argument pour être une liste vide [] . Ce devrait plutôt être un défaut. En raison de la façon dont les objets Python fonctionnent, ceux-ci doivent être définis à l'intérieur de la fonction, et non dans les arguments.

Voici une fonction de travail:

def list_flatten(l, a=None):
    #check a
    if a is None:
        #initialize with empty list
        a = []

    for i in l:
        if isinstance(i, list):
            list_flatten(i, a)
        else:
            a.append(i)
    return a

Test:

In [2]: lst = [1, 2, [3], [[4]],[5,[6]]]

In [3]: lst
Out[3]: [1, 2, [3], [[4]], [5, [6]]]

In [11]: list_flatten(lst)
Out[11]: [1, 2, 3, 4, 5, 6]
8
répondu Deleet 2016-11-29 03:45:43
def flatten(l, a):
    for i in l:
        if isinstance(i, list):
            flatten(i, a)
        else:
            a.append(i)
    return a

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

# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]
7
répondu Anil 2016-11-28 08:48:33

la suite me semble la plus simple:

>>> import numpy as np
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> print (np.concatenate(l))
[1 2 3 4 5 6 7 8 9]
7
répondu devil in the detail 2017-07-05 05:14:38

on peut aussi utiliser flat :

import numpy as np
list(np.array(l).flat)

Edit 11/02/2016: ne fonctionne que lorsque les sous-listes ont des dimensions identiques.

6
répondu mdh 2016-11-02 09:59:40

matplotlib.cbook.flatten() fonctionne pour les listes emboîtées même si elles nichent plus profondément que l'exemple.

import matplotlib
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
print(list(matplotlib.cbook.flatten(l)))
l2 = [[1, 2, 3], [4, 5, 6], [7], [8, [9, 10, [11, 12, [13]]]]]
print list(matplotlib.cbook.flatten(l2))

résultat:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

c'est 18x plus rapide que underscore._.aplatir:

Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636
6
répondu EL_DON 2018-07-20 18:16:43

code Simple pour underscore.py ventilateur de l'ensemble

from underscore import _
_.flatten([[1, 2, 3], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Il résout tous les aplatir problèmes (aucun élément de liste ou complexe imbrication)

from underscore import _
# 1 is none list item
# [2, [3]] is complex nesting
_.flatten([1, [2, [3]], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

vous pouvez installer underscore.py avec pip

pip install underscore.py
5
répondu Vu Anh 2017-03-25 05:09:57
def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])
4
répondu englealuze 2017-08-08 14:59:07

vous pouvez utiliser numpy :

flat_list = list(np.concatenate(list_of_list))

4
répondu A. Attia 2018-07-24 09:11:26

si vous êtes prêt à renoncer à une petite quantité de vitesse pour un look plus propre, alors vous pouvez utiliser numpy.concatenate().tolist() ou numpy.concatenate().ravel().tolist() :

import numpy

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] * 99

%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop

%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop

%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop

vous pouvez en savoir plus ici dans le docs numpy.concaténate et numpy.ravel

3
répondu mkultra 2016-10-27 03:31:54
flat_list = []
for i in list_of_list:
    flat_list+=i

ce Code fonctionne aussi très bien comme il étend juste la liste tout le chemin. Bien qu'il soit très similaire, mais ont seulement un pour boucle. Il a donc moins de complexité que d'ajouter 2 pour les boucles.

3
répondu Deepak Yadav 2018-06-20 11:12:25

la solution la plus rapide que j'ai trouvée (pour une grande liste de toute façon):

import numpy as np
#turn list into an array and flatten()
np.array(l).flatten()

fait! Vous pouvez bien sûr le retourner dans une liste en exécutant list(l)

2
répondu Canuck 2016-11-28 21:09:09

j'ai récemment rencontré une situation où j'avais un mélange de chaînes et de données numériques dans des sous-listes telles que

test = ['591212948',
['special', 'assoc', 'of', 'Chicago', 'Jon', 'Doe'],
['Jon'],
['Doe'],
['fl'],
92001,
555555555,
'hello',
['hello2', 'a'],
'b',
['hello33', ['z', 'w'], 'b']]

où des méthodes comme flat_list = [item for sublist in test for item in sublist] n'ont pas fonctionné. Donc, j'ai trouvé la solution suivante pour le niveau 1+ des sous-listes

def concatList(data):
    results = []
    for rec in data:
        if type(rec) == list:
            results += rec
            results = concatList(results)
        else:
            results.append(rec)
    return results

et le résultat

In [38]: concatList(test)
Out[38]:
 Out[60]:
['591212948',
'special',
'assoc',
'of',
'Chicago',
'Jon',
'Doe',
'Jon',
'Doe',
'fl',
92001,
555555555,
'hello',
'hello2',
'a',
'b',
'hello33',
'z',
'w',
'b']
2
répondu Jon 2017-09-21 19:54:13

une Autre approche inhabituelle qui fonctionne pour les hétéro - homogène et des listes d'entiers:

from typing import List


def flatten(l: list) -> List[int]:
    """Flatten an arbitrary deep nested list of lists of integers.

    Examples:
        >>> flatten([1, 2, [1, [10]]])
        [1, 2, 1, 10]

    Args:
        l: Union[l, Union[int, List[int]]

    Returns:
        Flatted list of integer
    """
    return [int(i.strip('[ ]')) for i in str(l).split(',')]
2
répondu tharndt 2018-09-13 11:34:20

la réponse acceptée ne me convenait pas lorsqu'il s'agissait de listes textuelles de longueurs variables. Voici une autre méthode qui a fonctionné pour moi.

l = ['aaa', 'bb', 'cccccc', ['xx', 'yyyyyyy']]

Accepté de répondre que pas "151970920 de travail":

flat_list = [item for sublist in l for item in sublist]
print(flat_list)
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'c', 'xx', 'yyyyyyy']

Nouvelle solution proposée qui a de travail pour moi:

flat_list = []
_ = [flat_list.extend(item) if isinstance(item, list) else flat_list.append(item) for item in l if item]
print(flat_list)
['aaa', 'bb', 'cccccc', 'xx', 'yyyyyyy']
2
répondu user9074332 2018-10-12 01:32:31

vous pouvez éviter les appels récursifs à la pile en utilisant une structure de données de pile réelle assez simplement.

alist = [1,[1,2],[1,2,[4,5,6],3, "33"]]
newlist = []

while len(alist) > 0 :
  templist = alist.pop()
  if type(templist) == type(list()) :
    while len(templist) > 0 :
      temp = templist.pop()
      if type(temp) == type(list()) :
        for x in temp :
          templist.append(x)
      else :
        newlist.append(temp)
  else :
    newlist.append(templist)
print(list(reversed(newlist)))
1
répondu FredMan 2017-10-19 05:46:09

ce n'est peut-être pas le moyen le plus efficace, mais j'ai pensé à mettre un one-liner (en fait un deux-liner). Les deux versions fonctionneront sur des listes de hiérarchie imbriquées et exploiteront les fonctionnalités du langage (Python3.5) et la récursion.

def make_list_flat (l):
    flist = []
    flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
    return flist

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)

la sortie est

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

cela fonctionne en profondeur première manière. La récursion va vers le bas jusqu'à ce qu'il trouve un élément de non-liste, puis étend la variable locale flist et puis le renverse à la parent. Chaque fois que flist est retourné, il est étendu à flist du parent dans la liste de compréhension. Par conséquent, à la racine, une liste plate est retournée.

celui ci-dessus crée plusieurs listes locales et les renvoie qui sont utilisées pour étendre la liste du parent. Je pense que la solution pour cela pourrait être la création d'un gloabl flist , comme ci-dessous.

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
    flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]

make_list_flat(a)
print (flist)

La sortie est à nouveau

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

bien que je sois pas sûr en ce moment à propos de l'efficacité.

1
répondu phoxis 2018-05-20 08:47:32

Note : ci-dessous s'applique à Python 3.3+ car il utilise yield_from . six est aussi un paquet tiers, bien qu'il soit stable. Alternativement, vous pouvez utiliser sys.version .


dans le cas de obj = [[1, 2,], [3, 4], [5, 6]] , toutes les solutions ici sont bonnes, y compris la compréhension de liste et itertools.chain.from_iterable .

cependant, considérer ce cas légèrement plus complexe:

>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]

il y a plusieurs problèmes ici:

  • un élément, 6 , est juste un scalaire; il n'est pas itérable, donc les routes ci-dessus vont échouer ici.
  • un élément, 'abc' , est techniquement itérable (tous les str sont). Cependant, en lisant entre les lignes un peu, vous ne voulez pas traiter en tant que tel, vous voulez le traiter comme un seul élément.
  • l'élément final, [8, [9, 10]] est lui-même un imbriqué itérable. Compréhension de la liste de base et chain.from_iterable extraire seulement "1 niveau vers le bas."

vous pouvez y remédier comme suit:

>>> from collections import Iterable
>>> from six import string_types

>>> def flatten(obj):
...     for i in obj:
...         if isinstance(i, Iterable) and not isinstance(i, string_types):
...             yield from flatten(i)
...         else:
...             yield i


>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]

ici, vous vérifiez que le sous-élément (1) est itérable avec Iterable , un ABC de itertools , mais veulent également s'assurer que (2) l'élément est pas " chaîne de caractères."

1
répondu Brad Solomon 2018-06-19 19:38:25

exemple nettoyé @Deleet

from collections import Iterable

def flatten(l, a=[]):
    for i in l:
        if isinstance(i, Iterable):
            flatten(i, a)
        else:
            a.append(i)
    return a

daList = [[1,4],[5,6],[23,22,234,2],[2], [ [[1,2],[1,2]],[[11,2],[11,22]] ] ]

print(flatten(daList))

exemple: https://repl.it/G8mb/0

0
répondu Kevin Postal 2017-03-22 17:01:57