Aplatir une liste superficielle en Python [dupliquer]

cette question a déjà une réponse ici:

est-il une façon simple d'aplatir une liste d'itérables avec une compréhension de liste, ou à défaut, ce que vous considéreriez tous être la meilleure façon de une liste aussi superficielle, un équilibre entre la performance et la lisibilité?

j'ai essayé d'aplatir une telle liste avec une compréhension de liste imbriquée, comme ceci:

[image for image in menuitem for menuitem in list_of_menuitems]

mais je suis en difficulté de la variété NameError là, parce que le name 'menuitem' is not defined . Après googling et en regardant autour sur le débordement de pile, j'ai obtenu les résultats désirés avec un reduce déclaration:

reduce(list.__add__, map(lambda x: list(x), list_of_menuitems))

, Mais cette méthode est assez illisible parce que j'ai besoin que list(x) appelle là parce que x est un objet Django QuerySet .

Conclusion :

Merci à tous ceux qui ont contribué à cette question. Voici un résumé de ce que j'ai appris. Je fais aussi ceci un wiki de communauté au cas où d'autres voudraient ajouter ou corriger ces observations.

mon énoncé de réduction original est redondant et est mieux écrit de cette façon:

>>> reduce(list.__add__, (list(mi) for mi in list_of_menuitems))

C'est la syntaxe correcte pour une liste imbriquée compréhension (Brillant résumé dF !):

>>> [image for mi in list_of_menuitems for image in mi]

mais ni l'une ni l'autre de ces méthodes ne sont aussi efficaces que l'utilisation de itertools.chain :

>>> from itertools import chain
>>> list(chain(*list_of_menuitems))

et comme @cdleary note , il est probablement mieux de style à éviter * opérateur magique en utilisant chain.from_iterable comme ainsi:

>>> chain = itertools.chain.from_iterable([[1,2],[3],[5,89],[],[6]])
>>> print(list(chain))
>>> [1, 2, 3, 5, 89, 6]
358
demandé sur Prairiedogg 2009-01-02 08:40:31

23 réponses

si vous cherchez simplement à itérer sur une version aplatie de la structure de données et que vous n'avez pas besoin d'une séquence indexable, considérez les itértools .chaîne et société .

>>> list_of_menuitems = [['image00', 'image01'], ['image10'], []]
>>> import itertools
>>> chain = itertools.chain(*list_of_menuitems)
>>> print(list(chain))
['image00', 'image01', 'image10']

ça marchera sur tout ce qui est itérable, ce qui devrait inclure les itérables QuerySet s de Django, qu'il semble que vous utilisez dans la question.

Edit: C'est probablement aussi bon qu'un réduire de toute façon, parce que reduce aura les mêmes frais généraux pour copier les articles dans la liste qui est étendue. chain n'encourra ce (même) dépassement que si vous lancez list(chain) à la fin.

Meta-Edit: en fait, c'est moins de frais généraux que la solution proposée de la question, parce que vous jetez les listes temporaires que vous créez lorsque vous étendez l'original avec le temporaire.

Edit: As J. F. Sebastian dit itertools.chain.from_iterable évite le déballage et vous devriez utiliser cela pour éviter * magie, mais l'application timeit montre une différence de performance négligeable.

278
répondu cdleary 2017-05-23 12:26:37

tu l'as presque! La façon de faire des compressions de liste imbriquées est de mettre les déclarations for dans le même ordre qu'ils iraient dans les déclarations for imbriquées régulières.

ainsi, ce

for inner_list in outer_list:
    for item in inner_list:
        ...

correspond à

[... for inner_list in outer_list for item in inner_list]

Si vous voulez

[image for menuitem in list_of_menuitems for image in menuitem]
257
répondu dF. 2014-01-20 15:27:06

@S. Lott : vous m'avez inspiré pour écrire une application timeit.

j'ai pensé qu'il pourrait aussi varier en fonction du nombre de partitions (nombre d'itérateurs dans la liste des conteneurs) -- votre commentaire n'a pas mentionné combien de partitions il y avait parmi les trente éléments. Cette parcelle est aplatie mille articles dans chaque course, avec le nombre variable de cloisons. Les articles sont également répartis entre les cloisons.

Flattening Comparison

Code (Python 2.6):

#!/usr/bin/env python2.6

"""Usage: %prog item_count"""

from __future__ import print_function

import collections
import itertools
import operator
from timeit import Timer
import sys

import matplotlib.pyplot as pyplot

def itertools_flatten(iter_lst):
    return list(itertools.chain(*iter_lst))

def itertools_iterable_flatten(iter_iter):
    return list(itertools.chain.from_iterable(iter_iter))

def reduce_flatten(iter_lst):
    return reduce(operator.add, map(list, iter_lst))

def reduce_lambda_flatten(iter_lst):
    return reduce(operator.add, map(lambda x: list(x), [i for i in iter_lst]))

def comprehension_flatten(iter_lst):
    return list(item for iter_ in iter_lst for item in iter_)

METHODS = ['itertools', 'itertools_iterable', 'reduce', 'reduce_lambda',
           'comprehension']

def _time_test_assert(iter_lst):
    """Make sure all methods produce an equivalent value.
    :raise AssertionError: On any non-equivalent value."""
    callables = (globals()[method + '_flatten'] for method in METHODS)
    results = [callable(iter_lst) for callable in callables]
    if not all(result == results[0] for result in results[1:]):
        raise AssertionError

def time_test(partition_count, item_count_per_partition, test_count=10000):
    """Run flatten methods on a list of :param:`partition_count` iterables.
    Normalize results over :param:`test_count` runs.
    :return: Mapping from method to (normalized) microseconds per pass.
    """
    iter_lst = [[dict()] * item_count_per_partition] * partition_count
    print('Partition count:    ', partition_count)
    print('Items per partition:', item_count_per_partition)
    _time_test_assert(iter_lst)
    test_str = 'flatten(%r)' % iter_lst
    result_by_method = {}
    for method in METHODS:
        setup_str = 'from test import %s_flatten as flatten' % method
        t = Timer(test_str, setup_str)
        per_pass = test_count * t.timeit(number=test_count) / test_count
        print('%20s: %.2f usec/pass' % (method, per_pass))
        result_by_method[method] = per_pass
    return result_by_method

if __name__ == '__main__':
    if len(sys.argv) != 2:
        raise ValueError('Need a number of items to flatten')
    item_count = int(sys.argv[1])
    partition_counts = []
    pass_times_by_method = collections.defaultdict(list)
    for partition_count in xrange(1, item_count):
        if item_count % partition_count != 0:
            continue
        items_per_partition = item_count / partition_count
        result_by_method = time_test(partition_count, items_per_partition)
        partition_counts.append(partition_count)
        for method, result in result_by_method.iteritems():
            pass_times_by_method[method].append(result)
    for method, pass_times in pass_times_by_method.iteritems():
        pyplot.plot(partition_counts, pass_times, label=method)
    pyplot.legend()
    pyplot.title('Flattening Comparison for %d Items' % item_count)
    pyplot.xlabel('Number of Partitions')
    pyplot.ylabel('Microseconds')
    pyplot.show()

Edit: a Décidé de rendre wiki de la communauté.

Note: METHODS devrait probablement être accumulé avec un décorateur, mais je me dis que ce serait plus facile pour les gens de lire de cette façon.

125
répondu cdleary 2017-05-23 12:10:41

sum(list of lists, []) l'aplatirait.

l = [['image00', 'image01'], ['image10'], []]
print sum(l,[]) # prints ['image00', 'image01', 'image10']
44
répondu Prem Anand 2015-06-14 03:50:21

Cette solution fonctionne pour des profondeurs de nidification arbitraires - pas seulement la" liste des listes " profondeur que certains (tous?) les autres solutions sont limitées à:

def flatten(x):
    result = []
    for el in x:
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

c'est la récursion qui permet un enchevêtrement de profondeur arbitraire - jusqu'à ce que vous atteigniez la profondeur maximale de récursion, bien sûr...

36
répondu James Brady 2009-01-05 00:12:19

Résultats De La Performance. Réviser.

import itertools
def itertools_flatten( aList ):
    return list( itertools.chain(*aList) )

from operator import add
def reduce_flatten1( aList ):
    return reduce(add, map(lambda x: list(x), [mi for mi in aList]))

def reduce_flatten2( aList ):
    return reduce(list.__add__, map(list, aList))

def comprehension_flatten( aList ):
    return list(y for x in aList for y in x)

j'ai aplati une liste à 2 niveaux de 30 articles 1000 fois

itertools_flatten     0.00554
comprehension_flatten 0.00815
reduce_flatten2       0.01103
reduce_flatten1       0.01404

Réduire est toujours un mauvais choix.

22
répondu S.Lott 2009-01-02 21:10:06

en python 2.6, en utilisant chain.from_iterable() :

>>> from itertools import chain
>>> list(chain.from_iterable(mi.image_set.all() for mi in h.get_image_menu()))

il évite la création de liste intermédiaire.

22
répondu jfs 2009-01-04 19:37:56

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
15
répondu Meitham 2016-04-04 08:23:26

du haut de ma tête, vous pouvez éliminer la lambda:

reduce(list.__add__, map(list, [mi.image_set.all() for mi in list_of_menuitems]))

Ou même éliminer la carte, puisque vous avez déjà une liste-comp:

reduce(list.__add__, [list(mi.image_set.all()) for mi in list_of_menuitems])

vous pouvez aussi simplement exprimer ceci comme une somme de listes:

sum([list(mi.image_set.all()) for mi in list_of_menuitems], [])
8
répondu recursive 2009-01-02 06:00:54

Voici la solution correcte en utilisant les compréhensions de liste (ils sont en arrière dans la question):

>>> join = lambda it: (y for x in it for y in x)
>>> list(join([[1,2],[3,4,5],[]]))
[1, 2, 3, 4, 5]

dans votre cas, ce serait

[image for menuitem in list_of_menuitems for image in menuitem.image_set.all()]

ou vous pouvez utiliser join et dire

join(menuitem.image_set.all() for menuitem in list_of_menuitems)

dans les deux cas, le gotcha était le nid des boucles for .

7
répondu Josh Lee 2009-01-02 07:33:49

avez-vous essayé aplatir? De matplotlib.cbook.aplatir (seq, scalarp=) ?

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

run("list(flatten(l))")
         3732 function calls (3303 primitive calls) in 0.007 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.007    0.007 <string>:1(<module>)
      429    0.001    0.000    0.001    0.000 cbook.py:475(iterable)
      429    0.002    0.000    0.003    0.000 cbook.py:484(is_string_like)
      429    0.002    0.000    0.006    0.000 cbook.py:565(is_scalar_or_string)
  727/298    0.001    0.000    0.007    0.000 cbook.py:605(flatten)
      429    0.000    0.000    0.001    0.000 core.py:5641(isMaskedArray)
      858    0.001    0.000    0.001    0.000 {isinstance}
      429    0.000    0.000    0.000    0.000 {iter}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



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

run("list(flatten(l))")
         7461 function calls (6603 primitive calls) in 0.007 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.007    0.007 <string>:1(<module>)
      858    0.001    0.000    0.001    0.000 cbook.py:475(iterable)
      858    0.002    0.000    0.003    0.000 cbook.py:484(is_string_like)
      858    0.002    0.000    0.006    0.000 cbook.py:565(is_scalar_or_string)
 1453/595    0.001    0.000    0.007    0.000 cbook.py:605(flatten)
      858    0.000    0.000    0.001    0.000 core.py:5641(isMaskedArray)
     1716    0.001    0.000    0.001    0.000 {isinstance}
      858    0.000    0.000    0.000    0.000 {iter}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



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

run("list(flatten(l))")
         11190 function calls (9903 primitive calls) in 0.010 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.010    0.010 <string>:1(<module>)
     1287    0.002    0.000    0.002    0.000 cbook.py:475(iterable)
     1287    0.003    0.000    0.004    0.000 cbook.py:484(is_string_like)
     1287    0.002    0.000    0.009    0.000 cbook.py:565(is_scalar_or_string)
 2179/892    0.001    0.000    0.010    0.000 cbook.py:605(flatten)
     1287    0.001    0.000    0.001    0.000 core.py:5641(isMaskedArray)
     2574    0.001    0.000    0.001    0.000 {isinstance}
     1287    0.000    0.000    0.000    0.000 {iter}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



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

run("list(flatten(l))")
         14919 function calls (13203 primitive calls) in 0.013 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.013    0.013 <string>:1(<module>)
     1716    0.002    0.000    0.002    0.000 cbook.py:475(iterable)
     1716    0.004    0.000    0.006    0.000 cbook.py:484(is_string_like)
     1716    0.003    0.000    0.011    0.000 cbook.py:565(is_scalar_or_string)
2905/1189    0.002    0.000    0.013    0.000 cbook.py:605(flatten)
     1716    0.001    0.000    0.001    0.000 core.py:5641(isMaskedArray)
     3432    0.001    0.000    0.001    0.000 {isinstance}
     1716    0.001    0.000    0.001    0.000 {iter}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler'

mise à JOUR Ce qui m'a donné une autre idée:

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

run("flattenlist(l)")
         564 function calls (432 primitive calls) in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    133/1    0.000    0.000    0.000    0.000 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
      429    0.000    0.000    0.000    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



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

run("flattenlist(l)")
         1125 function calls (861 primitive calls) in 0.001 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    265/1    0.001    0.000    0.001    0.001 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.000    0.000    0.001    0.001 <string>:1(<module>)
      858    0.000    0.000    0.000    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



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

run("flattenlist(l)")
         1686 function calls (1290 primitive calls) in 0.001 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    397/1    0.001    0.000    0.001    0.001 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1287    0.000    0.000    0.000    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



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

run("flattenlist(l)")
         2247 function calls (1719 primitive calls) in 0.002 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    529/1    0.001    0.000    0.002    0.002 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.000    0.000    0.002    0.002 <string>:1(<module>)
     1716    0.001    0.000    0.001    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



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

run("flattenlist(l)")
         22443 function calls (17163 primitive calls) in 0.016 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   5281/1    0.011    0.000    0.016    0.016 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.000    0.000    0.016    0.016 <string>:1(<module>)
    17160    0.005    0.000    0.005    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

donc pour tester son efficacité quand la récursive s'enfonce: à quel point?

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

new=[l]*33

run("flattenlist(new)")
         740589 function calls (566316 primitive calls) in 0.418 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 174274/1    0.281    0.000    0.417    0.417 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.001    0.001    0.418    0.418 <string>:1(<module>)
   566313    0.136    0.000    0.136    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



new=[l]*66

run("flattenlist(new)")
         1481175 function calls (1132629 primitive calls) in 0.809 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 348547/1    0.542    0.000    0.807    0.807 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.002    0.002    0.809    0.809 <string>:1(<module>)
  1132626    0.266    0.000    0.266    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



new=[l]*99

run("flattenlist(new)")
         2221761 function calls (1698942 primitive calls) in 1.211 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 522820/1    0.815    0.000    1.208    1.208 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.002    0.002    1.211    1.211 <string>:1(<module>)
  1698939    0.393    0.000    0.393    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



new=[l]*132

run("flattenlist(new)")
         2962347 function calls (2265255 primitive calls) in 1.630 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 697093/1    1.091    0.000    1.627    1.627 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.003    0.003    1.630    1.630 <string>:1(<module>)
  2265252    0.536    0.000    0.536    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



new=[l]*1320

run("flattenlist(new)")
         29623443 function calls (22652523 primitive calls) in 16.103 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
6970921/1   10.842    0.000   16.069   16.069 <ipython-input-55-39b139bad497>:4(flattenlist)
        1    0.034    0.034   16.103   16.103 <string>:1(<module>)
 22652520    5.227    0.000    5.227    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

je parie "flattenlist" que je vais utiliser ce plutôt que matploblib pour une longue période à moins que je veux un générateur de rendement et résultat rapide comme "aplatir" les utilisations dans matploblib.cbook

C'est rapide.

  • et voici le code

:

typ=(list,tuple)


def flattenlist(d):
    thelist = []
    for x in d:
        if not isinstance(x,typ):
            thelist += [x]
        else:
            thelist += flattenlist(x)
    return thelist
3
répondu user2290820 2013-12-05 13:17:27

cette version est un générateur.Ajuster si vous voulez une liste.

def list_or_tuple(l):
    return isinstance(l,(list,tuple))
## predicate will select the container  to be flattened
## write your own as required
## this one flattens every list/tuple


def flatten(seq,predicate=list_or_tuple):        
    ## recursive generator 
    for i in seq:
        if predicate(seq):
            for j in flatten(i):
                yield j
        else:
            yield i

vous pouvez ajouter un prédicat, si vous voulez aplatir ceux qui satisfont une condition

tiré de Python cookbook

3
répondu devsaw 2013-12-23 09:33:20

D'après mon expérience, la façon la plus efficace d'aplanir une liste de listes est:

flat_list = []
map(flat_list.extend, list_of_list)

quelques comparaisons avec les autres méthodes proposées:

list_of_list = [range(10)]*1000
%timeit flat_list=[]; map(flat_list.extend, list_of_list)
#10000 loops, best of 3: 119 µs per loop
%timeit flat_list=list(itertools.chain.from_iterable(list_of_list))
#1000 loops, best of 3: 210 µs per loop
%timeit flat_list=[i for sublist in list_of_list for i in sublist]
#1000 loops, best of 3: 525 µs per loop
%timeit flat_list=reduce(list.__add__,list_of_list)
#100 loops, best of 3: 18.1 ms per loop

maintenant, le gain d'efficacité apparaît mieux lors du traitement de sous-listes plus longues:

list_of_list = [range(1000)]*10
%timeit flat_list=[]; map(flat_list.extend, list_of_list)
#10000 loops, best of 3: 60.7 µs per loop
%timeit flat_list=list(itertools.chain.from_iterable(list_of_list))
#10000 loops, best of 3: 176 µs per loop

et cette méthode fonctionne aussi avec n'importe quel objet itératif:

class SquaredRange(object):
    def __init__(self, n): 
        self.range = range(n)
    def __iter__(self):
        for i in self.range: 
            yield i**2

list_of_list = [SquaredRange(5)]*3
flat_list = []
map(flat_list.extend, list_of_list)
print flat_list
#[0, 1, 4, 9, 16, 0, 1, 4, 9, 16, 0, 1, 4, 9, 16]
3
répondu Juh_ 2014-01-20 15:19:35

Voici une version qui fonctionne pour plusieurs niveaux de liste en utilisant collectons.Iterable :

import collections

def flatten(o):
    result = []
    for i in o:
        if isinstance(i, collections.Iterable):
            result.extend(flatten(i))
        else:
            result.append(i)
    return result
3
répondu Pierre Thibault 2014-12-15 06:03:05

Ce sujet:

from operator import add
reduce(add, map(lambda x: list(x.image_set.all()), [mi for mi in list_of_menuitems]))

mais Guido recommande de ne pas faire trop dans une seule ligne de code car cela réduit la lisibilité. Il y a un gain de performance minime, s'il y en a un, en exécutant ce que vous voulez dans une seule ligne par rapport à plusieurs lignes.

2
répondu daniel 2009-01-02 06:28:58

pylab fournit un: lien vers numpy aplatir

2
répondu ntg 2014-02-22 17:01:33

si vous recherchez une doublure intégrée, simple, vous pouvez utiliser:

a = [[1, 2, 3], [4, 5, 6]
b = [i[x] for i in a for x in range(len(i))]
print b

retourne

[1, 2, 3, 4, 5, 6]
2
répondu Bottersnike 2015-08-27 15:39:06

si chaque élément de la liste est une chaîne de caractères (et que les chaînes à l'intérieur de ces chaînes utilisent ""plutôt que""), vous pouvez utiliser des expressions régulières ( re module)

>>> flattener = re.compile("\'.*?\'")
>>> flattener
<_sre.SRE_Pattern object at 0x10d439ca8>
>>> stred = str(in_list)
>>> outed = flattener.findall(stred)

le code ci-dessus convertit in_list en chaîne de caractères, utilise le regex pour trouver tous les substrats dans les guillemets (c.-à-d. chaque élément de la liste) et les crache comme une liste.

1
répondu user22723 2014-12-03 20:06:19

si vous devez aplatir une liste plus compliquée avec des éléments non itérables ou avec une profondeur supérieure à 2, Vous pouvez utiliser la fonction suivante:

def flat_list(list_to_flat):
    if not isinstance(list_to_flat, list):
        yield list_to_flat
    else:
        for item in list_to_flat:
            yield from flat_list(item)

il retournera l'objet Générateur que vous pouvez convertir en liste avec la fonction list() . Notez que la syntaxe yield from est disponible en python3.3 mais vous pouvez utiliser l'itération explicite à la place.

Exemple:

>>> a = [1, [2, 3], [1, [2, 3, [1, [2, 3]]]]]
>>> print(list(flat_list(a)))
[1, 2, 3, 1, 2, 3, 1, 2, 3]
1
répondu DartLenin 2015-04-12 01:05:48

Une alternative simple est d'utiliser numpy de concaténer mais il convertit le contenu de flotteur:

import numpy as np
print np.concatenate([[1,2],[3],[5,89],[],[6]])
# array([  1.,   2.,   3.,   5.,  89.,   6.])
print list(np.concatenate([[1,2],[3],[5,89],[],[6]]))
# [  1.,   2.,   3.,   5.,  89.,   6.]
1
répondu strpeter 2015-10-14 08:29:29

la façon la plus simple d'y parvenir en Python 2 ou 3 est d'utiliser la bibliothèque morph en utilisant pip install morph .

le code est:

import morph

list = [[1,2],[3],[5,89],[],[6]]
flattened_list = morph.flatten(list)  # returns [1, 2, 3, 5, 89, 6]
1
répondu YPCrumble 2015-12-17 17:43:33
def flatten(items):
    for i in items:
        if hasattr(i, '__iter__'):
            for m in flatten(i):
                yield m
        else:
            yield i

essai:

print list(flatten2([1.0, 2, 'a', (4,), ((6,), (8,)), (((8,),(9,)), ((12,),(10)))]))
1
répondu kopos 2016-04-05 13:28:16

Dans Python 3.4 , vous serez en mesure de le faire:

[*innerlist for innerlist in outer_list]
0
répondu elyase 2013-09-27 14:42:38