web-dev-qa-db-fra.com

Aplatir une liste de listes irrégulière

Oui, je sais que ce sujet a déjà été traité ( ici , ici , ici , ici ), mais pour autant que je sache, toutes les solutions, sauf une, échouer sur une liste comme celle-ci:

L = [[[1, 2, 3], [4, 5]], 6]

Où la sortie souhaitée est

[1, 2, 3, 4, 5, 6]

Ou peut-être même mieux, un itérateur. La seule solution que j'ai vue qui fonctionne pour une imbrication arbitraire est trouvée dans cette question :

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

flatten(L)

Est-ce le meilleur modèle? Ai-je oublié quelque chose? Des problèmes?

374
telliott99

L'utilisation des fonctions du générateur peut rendre votre exemple un peu plus facile à lire et probablement améliorer les performances.

Python 2

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flatten(el):
                yield sub
        else:
            yield el

J'ai utilisé le Iterable ABC ajouté dans 2.6.

Python 3

Dans Python 3, la variable basestring n'est plus, mais vous pouvez utiliser un nuplet de str et bytes pour obtenir le même effet.

L'opérateur yield from renvoie un élément d'un générateur à la fois. Cette syntaxe pour déléguer à un sous-générateur a été ajoutée dans 3.3

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el
331
Cristian

Ma solution:

def flatten(x):
    if isinstance(x, collections.Iterable):
        return [a for i in x for a in flatten(i)]
    else:
        return [x]

Un peu plus concis, mais à peu près pareil.

46
Josh Lee

Version génératrice de la solution non-récursive de @ unutbu, comme l'a demandé @Andrew dans un commentaire:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        yield l[i]
        i += 1

Version légèrement simplifiée de ce générateur:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    while l:
        while l and isinstance(l[0], ltypes):
            l[0:1] = l[0]
        if l: yield l.pop(0)
33
Alex Martelli

Générateur utilisant la récursion et la frappe de canard (mis à jour pour Python 3):

def flatten(L):
    for item in L:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

list(flatten([[[1, 2, 3], [4, 5]], 6]))
>>>[1, 2, 3, 4, 5, 6]
32
dansalmo

Cette version de flatten évite la limite de récursivité de python (et fonctionne donc avec des itérables imbriquées de manière arbitraire, profonde) C'est un générateur capable de gérer des chaînes et des itérables arbitraires (même infinis).

import itertools as IT
import collections

def flatten(iterable, ltypes=collections.Iterable):
    remainder = iter(iterable)
    while True:
        first = next(remainder)
        if isinstance(first, ltypes) and not isinstance(first, basestring):
            remainder = IT.chain(first, remainder)
        else:
            yield first

Voici quelques exemples démontrant son utilisation:

print(list(IT.islice(flatten(IT.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

print(list(IT.islice(flatten(IT.chain(IT.repeat(2,3),
                                       {10,20,30},
                                       'foo bar'.split(),
                                       IT.repeat(1),)),10)))
# [2, 2, 2, 10, 20, 30, 'foo', 'bar', 1, 1]

print(list(flatten([[1,2,[3,4]]])))
# [1, 2, 3, 4]

seq = ([[chr(i),chr(i-32)] for i in xrange(ord('a'), ord('z')+1)] + range(0,9))
print(list(flatten(seq)))
# ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H',
# 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P',
# 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X',
# 'y', 'Y', 'z', 'Z', 0, 1, 2, 3, 4, 5, 6, 7, 8]

Bien que flatten puisse gérer des générateurs infinis, il ne peut pas gérer une imbrication infinie:

def infinitely_nested():
    while True:
        yield IT.chain(infinitely_nested(), IT.repeat(1))

print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs
25
unutbu

Voici ma version fonctionnelle de aplatissement récursif, qui gère à la fois les nuplets et les listes, et vous permet d'ajouter n'importe quel mélange d'arguments de position. Retourne un générateur qui produit la séquence complète dans l'ordre, arg par arg:

flatten = lambda *n: (e for a in n
    for e in (flatten(*a) if isinstance(a, (Tuple, list)) else (a,)))

Usage:

l1 = ['a', ['b', ('c', 'd')]]
l2 = [0, 1, (2, 3), [[4, 5, (6, 7, (8,), [9]), 10]], (11,)]
print list(flatten(l1, -2, -1, l2))
['a', 'b', 'c', 'd', -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
21
samplebias

Voici une autre réponse encore plus intéressante ...

import re

def Flatten(TheList):
    a = str(TheList)
    b,crap = re.subn(r'[\[,\]]', ' ', a)
    c = b.split()
    d = [int(x) for x in c]

    return(d)

Fondamentalement, il convertit la liste imbriquée en chaîne, utilise une expression rationnelle pour supprimer la syntaxe imbriquée, puis reconvertit le résultat en une liste (aplatie).

13
clay
def flatten(xs):
    res = []
    def loop(ys):
        for i in ys:
            if isinstance(i, list):
                loop(i)
            else:
                res.append(i)
    loop(xs)
    return res
10
kev

Vous pouvez utiliser deepflatten du package tiers iteration_utilities :

>>> from iteration_utilities import deepflatten
>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(deepflatten(L))
[1, 2, 3, 4, 5, 6]

>>> list(deepflatten(L, types=list))  # only flatten "inner" lists
[1, 2, 3, 4, 5, 6]

C'est un itérateur, vous devez donc l'itérer (par exemple en l'enveloppant avec list ou en l'utilisant dans une boucle). En interne, il utilise une approche itérative au lieu d'une approche récursive. Il est écrit en tant qu'extension C et peut donc être plus rapide que les approches python pures:

>>> %timeit list(deepflatten(L))
12.6 µs ± 298 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit list(deepflatten(L, types=list))
8.7 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> %timeit list(flatten(L))   # Cristian - Python 3.x approach from https://stackoverflow.com/a/2158532/5393381
86.4 µs ± 4.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(flatten(L))   # Josh Lee - https://stackoverflow.com/a/2158522/5393381
107 µs ± 2.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(genflat(L, list))  # Alex Martelli - https://stackoverflow.com/a/2159079/5393381
23.1 µs ± 710 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Je suis l'auteur de la bibliothèque iteration_utilities.

7
MSeifert

C'était amusant d'essayer de créer une fonction qui pouvait aplatir une liste irrégulière en Python, mais bien sûr, c'est à cela que sert Python (pour rendre la programmation amusante). Le générateur suivant fonctionne assez bien avec quelques mises en garde:

def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable

Il va aplatir les types de données que vous voudrez peut-être laisser seuls (tels que les objets bytearray, bytes et str). En outre, le code repose sur le fait que demander un itérateur à un non-itérable soulève une TypeError.

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable


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

Modifier:

Je ne suis pas d'accord avec la mise en œuvre précédente. Le problème est que vous ne devriez pas être en mesure d’aplatir quelque chose qui n’est pas itérable. C'est déroutant et donne une fausse impression de l'argument.

>>> list(flatten(123))
[123]
>>>

Le générateur suivant est presque identique au premier mais n’a pas le problème de vouloir aplatir un objet non-itérable. Il échoue comme on pourrait s'y attendre lorsqu'un argument inapproprié lui est donné.

def flatten(iterable):
    for item in iterable:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

Tester le générateur fonctionne bien avec la liste fournie. Cependant, le nouveau code générera une TypeError lorsqu'un objet non-iterable lui est donné. Des exemples sont présentés ci-dessous du nouveau comportement.

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>> list(flatten(123))
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    list(flatten(123))
  File "<pyshell#27>", line 2, in flatten
    for item in iterable:
TypeError: 'int' object is not iterable
>>>
6
Noctis Skytower

Bien qu'une réponse élégante et très Pythonique ait été sélectionnée, je présenterais ma solution uniquement pour l'examen:

def flat(l):
    ret = []
    for i in l:
        if isinstance(i, list) or isinstance(i, Tuple):
            ret.extend(flat(i))
        else:
            ret.append(i)
    return ret

S'il vous plaît dites à quel point ce code est bon ou mauvais?

4
Xolve

Voici une fonction simple qui aplatit les listes de profondeur arbitraire. Pas de récursivité, pour éviter le débordement de pile.

from copy import deepcopy

def flatten_list(nested_list):
    """Flatten an arbitrarily nested list, without recursion (to avoid
    stack overflows). Returns a new list, the original list is unchanged.

    >> list(flatten_list([1, 2, 3, [4], [], [[[[[[[[[5]]]]]]]]]]))
    [1, 2, 3, 4, 5]
    >> list(flatten_list([[1, 2], 3]))
    [1, 2, 3]

    """
    nested_list = deepcopy(nested_list)

    while nested_list:
        sublist = nested_list.pop(0)

        if isinstance(sublist, list):
            nested_list = sublist + nested_list
        else:
            yield sublist
4
Wilfred Hughes

Je préfère les réponses simples. Pas de générateurs. Aucune récursion ou limite de récursivité. Juste itération:

def flatten(TheList):
    listIsNested = True

    while listIsNested:                 #outer loop
        keepChecking = False
        Temp = []

        for element in TheList:         #inner loop
            if isinstance(element,list):
                Temp.extend(element)
                keepChecking = True
            else:
                Temp.append(element)

        listIsNested = keepChecking     #determine if outer loop exits
        TheList = Temp[:]

    return TheList

Cela fonctionne avec deux listes: une boucle for interne et une boucle while externe. 

La boucle for interne parcourt la liste. S'il trouve un élément de la liste, il (1) utilise list.extend () pour aplatir le niveau d'imbrication de la première partie et (2) rétablit keepChecking à True. Keepchecking est utilisé pour contrôler la boucle while externe. Si la boucle externe est définie sur true, elle déclenche la boucle interne pour une autre passe. 

Ces passes continuent jusqu'à ce qu'il n'y ait plus de listes imbriquées. Lorsqu'une passe survient enfin sans trouver d'objet, keepChecking n'est jamais déclenchée à true, ce qui signifie que listIsNested reste false et que la boucle while externe se ferme. 

La liste aplatie est ensuite renvoyée.

Essai 

flatten([1,2,3,4,[100,200,300,[1000,2000,3000]]])

[1, 2, 3, 4, 100, 200, 300, 1000, 2000, 3000]

4
clay

Voici l'implémentation compiler.ast.flatten dans 2.7.5:

def flatten(seq):
    l = []
    for elt in seq:
        t = type(elt)
        if t is Tuple or t is list:
            for elt2 in flatten(elt):
                l.append(elt2)
        else:
            l.append(elt)
    return l

Il existe de meilleures méthodes plus rapides (si vous êtes arrivé ici, vous les avez déjà vues)

Notez aussi:

Déconseillé depuis la version 2.6: Le package du compilateur a été supprimé de Python 3.

2
pradyunsg

Je n'ai pas passé en revue toutes les réponses déjà disponibles, mais voici un modèle que j'ai proposé, empruntant à la méthode de traitement des listes LISP et de la liste de repos du LISP. 

def flatten(l): return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]

voici un cas simple et un cas pas si simple -

>>> flatten([1,[2,3],4])
[1, 2, 3, 4]

>>> flatten([1, [2, 3], 4, [5, [6, {'name': 'some_name', 'age':30}, 7]], [8, 9, [10, [11, [12, [13, {'some', 'set'}, 14, [15, 'some_string'], 16], 17, 18], 19], 20], 21, 22, [23, 24], 25], 26, 27, 28, 29, 30])
[1, 2, 3, 4, 5, 6, {'age': 30, 'name': 'some_name'}, 7, 8, 9, 10, 11, 12, 13, set(['set', 'some']), 14, 15, 'some_string', 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
>>> 
2
Shreyas

Je suis surpris que personne n'y ait pensé. Putain de récursion Je ne reçois pas les réponses récursives que les gens avancés ont données ici. de toute façon voici ma tentative sur ce point. l'avertissement est qu'il est très spécifique au cas d'utilisation du PO

import re

L = [[[1, 2, 3], [4, 5]], 6]
flattened_list = re.sub("[\[\]]", "", str(L)).replace(" ", "").split(",")
new_list = list(map(int, flattened_list))
print(new_list)

sortie:

[1, 2, 3, 4, 5, 6]
2
Zion

Le moyen le plus simple consiste à utiliser la bibliothèque morph en utilisant pip install morph.

Le code est:

import morph

list = [[[1, 2, 3], [4, 5]], 6]
flattened_list = morph.flatten(list)  # returns [1, 2, 3, 4, 5, 6]
1
YPCrumble

totalement hacky mais je pense que cela fonctionnerait (en fonction de votre type de données)

flat_list = ast.literal_eval("[%s]"%re.sub("[\[\]]","",str(the_list)))
1
Joran Beasley

Voici une autre approche py2, je ne sais pas si c'est la plus rapide, la plus élégante ou la plus sûre ...

from collections import Iterable
from itertools import imap, repeat, chain


def flat(seqs, ignore=(int, long, float, basestring)):
    return repeat(seqs, 1) if any(imap(isinstance, repeat(seqs), ignore)) or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

Il peut ignorer tout type spécifique (ou dérivé) de votre choix, il retourne un itérateur, vous pouvez donc le convertir en un conteneur spécifique tel que list, Tuple, dict ou simplement le consommer afin de réduire l'encombrement mémoire, pour le meilleur ou pour le pire. il peut gérer des objets initiaux non-itérables tels que int ...

Notez que la plupart des tâches lourdes se font en C, car, autant que je sache, comment les outils sont implémentés, alors, bien que ce soit récursif, autant que je sache, il n’est pas limité par la profondeur de récursivité de python ne signifie pas que vous êtes limité par la mémoire, spécialement sous OS X où la taille de sa pile a une limite stricte à compter d'aujourd'hui (OS X Mavericks) ...

il existe une approche légèrement plus rapide, mais moins portable, utilisez-la uniquement si vous pouvez supposer que les éléments de base de l'entrée peuvent être explicitement déterminés, sinon vous obtiendrez une récursion infinie, et OS X avec sa taille de pile limitée jeter une faute de segmentation assez rapidement ...

def flat(seqs, ignore={int, long, float, str, unicode}):
    return repeat(seqs, 1) if type(seqs) in ignore or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

ici, nous utilisons des ensembles pour vérifier le type, il faut donc O(1) vs O (nombre de types) pour vérifier si un élément doit être ignoré, bien que toute valeur avec un type dérivé du type indiqué les types ignorés échouent, c’est pourquoi il utilise str, unicode alors utilisez-le avec prudence ...

tests:

import random

def test_flat(test_size=2000):
    def increase_depth(value, depth=1):
        for func in xrange(depth):
            value = repeat(value, 1)
        return value

    def random_sub_chaining(nested_values):
        for values in nested_values:
            yield chain((values,), chain.from_iterable(imap(next, repeat(nested_values, random.randint(1, 10)))))

    expected_values = Zip(xrange(test_size), imap(str, xrange(test_size)))
    nested_values = random_sub_chaining((increase_depth(value, depth) for depth, value in enumerate(expected_values)))
    assert not any(imap(cmp, chain.from_iterable(expected_values), flat(chain(((),), nested_values, ((),)))))

>>> test_flat()
>>> list(flat([[[1, 2, 3], [4, 5]], 6]))
[1, 2, 3, 4, 5, 6]
>>>  

$ uname -a
Darwin Samys-MacBook-Pro.local 13.3.0 Darwin Kernel Version 13.3.0: Tue Jun  3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64
$ python --version
Python 2.7.5
1
Samy Vilar

Je suis conscient qu'il y a déjà beaucoup de réponses géniales mais je voulais ajouter une réponse qui utilise la méthode de programmation fonctionnelle pour résoudre la question. Dans cette réponse, je me sers de la double récursivité:

def flatten_list(seq):
    if not seq:
        return []
    Elif isinstance(seq[0],list):
        return (flatten_list(seq[0])+flatten_list(seq[1:]))
    else:
        return [seq[0]]+flatten_list(seq[1:])

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

sortie:

[1, 2, 3, 4, 5, 6, 7]
1
Leo wahyd

Je ne suis pas sûr que ce soit nécessairement plus rapide ou plus efficace, mais voici ce que je fais:

def flatten(lst):
    return eval('[' + str(lst).replace('[', '').replace(']', '') + ']')

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

La fonction flatten transforme ici la liste en une chaîne, supprime tous des crochets, rattache les crochets aux extrémités et la reconstitue en liste. 

Cependant, si vous saviez que vous aviez des crochets dans votre liste, tels que [[1, 2], "[3, 4] and [5]"], vous auriez à faire autre chose.

1
diligar

Utiliser itertools.chain:

import itertools
from collections import Iterable

def list_flatten(lst):
    flat_lst = []
    for item in itertools.chain(lst):
        if isinstance(item, Iterable):
            item = list_flatten(item)
            flat_lst.extend(item)
        else:
            flat_lst.append(item)
    return flat_lst

Ou sans chaînage:

def flatten(q, final):
    if not q:
        return
    if isinstance(q, list):
        if not isinstance(q[0], list):
            final.append(q[0])
        else:
            flatten(q[0], final)
        flatten(q[1:], final)
    else:
        final.append(q)
1
Saksham Varma

Il suffit d'utiliser une bibliothèque funcy: pip install funcy

import funcy


funcy.flatten([[[[1, 1], 1], 2], 3]) # returns generator
funcy.lflatten([[[[1, 1], 1], 2], 3]) # returns list

1
ADR

J'ai utilisé récursif pour résoudreliste imbriquée avec une profondeur

def combine_nlist(nlist,init=0,combiner=lambda x,y: x+y):
    '''
    apply function: combiner to a nested list element by element(treated as flatten list)
    '''
    current_value=init
    for each_item in nlist:
        if isinstance(each_item,list):
            current_value =combine_nlist(each_item,current_value,combiner)
        else:
            current_value = combiner(current_value,each_item)
    return current_value

Donc, après avoir défini la fonction combine_nlist, il est facile d’utiliser cette fonction pour mettre à plat. Ou vous pouvez le combiner en une seule fonction. J'aime ma solution car elle peut être appliquée à n'importe quelle liste imbriquée.

def flatten_nlist(nlist):
    return combine_nlist(nlist,[],lambda x,y:x+[y])

résultat

In [379]: flatten_nlist([1,2,3,[4,5],[6],[[[7],8],9],10])
Out[379]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1
freeyoung

Solution itérative avec Python 3

Cette solution peut fonctionner avec tous les objets sauf str et bytes.

from collections import Iterable
from collections import Iterator


def flat_iter(obj):
    stack = [obj]
    while stack:
        element = stack.pop()
        if element and isinstance(element, Iterator):
            stack.append(element)
            try:
                stack.append(next(element))
            except StopIteration:
                stack.pop()
        Elif isinstance(element, Iterable) and not isinstance(element, (str, bytes)):
            stack.append(iter(element))
        else:
            yield element


tree_list = [[(1,2,3),(4,5,6, (7,8, 'next element is 5')), (5,6), [[[3,4,5],'foo1'],'foo2'],'foo3']]

not_iterable = 10

it1 = flat_iter(tree_list)
it2 = flat_iter(not_iterable)

print(list(it1))
print(list(it2))

[1, 2, 3, 4, 5, 6, 7, 8, 'le prochain élément est 5', 5, 6, 3, 4, 5, 'foo1', 'foo2', 'foo3']

[dix]

0
DeaD_EyE

c'est peut-être une vieille question, je voudrais tenter le coup.

Je suis un idiot alors je vais donner une solution "idiote". toute cette récursion me fait mal au cerveau.

flattened_list  = []
nested_list =[[[1, 2, 3], [4, 5]], 6]

def flatten(nested_list, container):
    for item in nested_list:
        if isintance(item, list):
            flatten(item)
        else:
            container.append(i)

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

Je comprends qu’il utilise un effet secondaire, mais c’est au mieux de ma compréhension de la récursivité qui peut aller

0
halcyonjuly7

Je ne vois rien de ce genre posté ici et venant d'une question fermée sur le même sujet, mais pourquoi ne pas simplement faire quelque chose comme ceci (si vous connaissez le type de la liste que vous voulez séparer):

>>> a = [1, 2, 3, 5, 10, [1, 25, 11, [1, 0]]]    
>>> g = str(a).replace('[', '').replace(']', '')    
>>> b = [int(x) for x in g.split(',') if x.strip()]

Vous auriez besoin de connaître le type des éléments, mais je pense que cela peut être généralisé et je pense que ce serait plus rapide.

0
Bogdan

Pas de récursivité ni de boucles imbriquées. Quelques lignes. Bien formaté et facile à lire:

def flatten_deep(arr: list):
""" Flattens arbitrarily-nested list `arr` into single-dimensional. """

while arr:
    if isinstance(arr[0], list):  # Checks whether first element is a list
        arr = arr[0] + arr[1:]  # If so, flattens that first element one level
    else:
        yield arr.pop(0)  # Otherwise yield as part of the flat array

flatten_deep(L)

À partir de mon propre code sur https://github.com/jorgeorpinel/flatten_nested_lists/blob/master/flatten.py

0
Jorge Orpinel

Ceci est un simple outil d'aplatissement sur python2

flatten=lambda l: reduce(lambda x,y:x+y,map(flatten,l),[]) if isinstance(l,list) else [l]

test=[[1,2,3,[3,4,5],[6,7,[8,9,[10,[11,[12,13,14]]]]]],]
print flatten(test)

#output [1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
0
Statham

Sans utiliser aucune bibliothèque:

def flat(l):
    def _flat(l, r):    
        if type(l) is not list:
            r.append(l)
        else:
            for i in l:
                r = r + flat(i)
        return r
    return _flat(l, [])



# example
test = [[1], [[2]], [3], [['a','b','c'] , [['z','x','y']], ['d','f','g']], 4]    
print flat(test) # prints [1, 2, 3, 'a', 'b', 'c', 'z', 'x', 'y', 'd', 'f', 'g', 4]
0
alfasin

Cela aplatira une liste ou un dictionnaire (ou une liste de listes ou de dictionnaires de dictionnaires, etc.). Il suppose que les valeurs sont des chaînes et crée une chaîne qui concatène chaque élément avec un argument de séparation. Si vous le souhaitez, vous pouvez utiliser le séparateur pour scinder ultérieurement le résultat en un objet de liste. Il utilise la récursivité si la valeur suivante est une liste ou une chaîne. Utilisez l'argument key pour indiquer si vous voulez les clés ou les valeurs (définir key sur false) de l'objet dictionnaire. 

def flatten_obj(n_obj, key=True, my_sep=''):
    my_string = ''
    if type(n_obj) == list:
        for val in n_obj:
            my_sep_setter = my_sep if my_string != '' else ''
            if type(val) == list or type(val) == dict:
                my_string += my_sep_setter + flatten_obj(val, key, my_sep)
            else:
                my_string += my_sep_setter + val
    Elif type(n_obj) == dict:
        for k, v in n_obj.items():
            my_sep_setter = my_sep if my_string != '' else ''
            d_val = k if key else v
            if type(v) == list or type(v) == dict:
                my_string += my_sep_setter + flatten_obj(v, key, my_sep)
            else:
                my_string += my_sep_setter + d_val
    Elif type(n_obj) == str:
        my_sep_setter = my_sep if my_string != '' else ''
        my_string += my_sep_setter + n_obj
        return my_string
    return my_string

print(flatten_obj(['just', 'a', ['test', 'to', 'try'], 'right', 'now', ['or', 'later', 'today'],
                [{'dictionary_test': 'test'}, {'dictionary_test_two': 'later_today'}, 'my power is 9000']], my_sep=', ')

rendements:

juste, un test, pour, essayer, bon, maintenant, ou, plus tard, aujourd'hui, dictionary_test, dictionary_test_two, mon pouvoir est de 9000

0
Matt Farguson

Je suis nouveau sur python et viens d'un fond de LISP. C’est ce que j’ai trouvé (regardez les noms de var pour lulz):

def flatten(lst):
    if lst:
        car,*cdr=lst
        if isinstance(car,(list,Tuple)):
            if cdr: return flatten(car) + flatten(cdr)
            return flatten(car)
        if cdr: return [car] + flatten(cdr)
        return [car]

Semble travailler. Tester:

flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))

résultats:

[1, 2, 3, 4, 5, 6, 7, 8, 1, 2]
0
Michael Puckett

Python-3

from collections import Iterable

L = [[[1, 2, 3], [4, 5]], 6,[7,[8,9,[10]]]]

def flatten(thing):
    result = []

    if isinstance(thing, Iterable):
        for item in thing:
            result.extend(flatten(item))
    else:
        result.append(thing)

    return result


flat = flatten(L)
print(flat)
0
Fuji Komalan

Nous pouvons également utiliser la fonction 'type' de python. Lors de l'itération de la liste, nous vérifions si l'élément est une liste ou non. Sinon, nous "ajoutons", sinon nous "l'étendrons". Voici un exemple de code - 

l=[1,2,[3,4],5,[6,7,8]]
x=[]
for i in l:
    if type(i) is list:
        x.extend(i)
    else:
        x.append(i)
print x

Sortie:

[1, 2, 3, 4, 5, 6, 7, 8]

Pour plus d'informations sur append () et extend (), consultez le site Web suivant: https://docs.python.org/2/tutorial/datastructures.html

0
noobcoder

Similaire à la réponse de diligar

weird_list=[[1, 2, 3], [4, 5, 6], [7], [8, 9]]
Nice_list = list(map(int, ''.join([e for e in str(weird_list) if e not in '[ ]']).split(',')))
0
whackamadoodle3000

De mon réponse précédente , cette fonction aplatit la plupart des cas auxquels je peux penser. Je crois que cela fonctionne en python 2.3.

def flatten(item, keepcls=(), keepobj=()):
    if not hasattr(item, '__iter__') or isinstance(item, keepcls) or item in keepobj:
        yield item
    else:
        for i in item:
            for j in flatten(i, keepcls, keepobj + (item,)):
                yield j

Listes circulaires

>>> list(flatten([1, 2, [...], 3]))
[1, 2, [1, 2, [...], 3], 3]

Depth premières listes

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

Listes répétées imbriquées:

>>> list(flatten([[1,2],[1,[1,2]],[1,2]]))
[1, 2, 1, 1, 2, 1, 2]

Listes avec des dicts (ou d'autres objets à ne pas aplatir)

>>> list(flatten([1,2, {'a':1, 'b':2}, 'text'], keepcls=(dict, str)))
[1, 2, {'a': 1, 'b': 2}, 'text']

Tous les iterables

>>> list(flatten((x for x in [1,2, set([3,(4,5),6])])))
[1, 2, 4, 5, 3, 6]

Vous voudrez peut-être conserver certaines classes par défaut dans keepcls pour pouvoir appeler la fonction plus laconique.

0
wihlke

Si vous aimez la récursion, cette solution pourrait vous intéresser:

def f(E):
    if E==[]: 
        return []
    Elif type(E) != list: 
        return [E]
    else:
        a = f(E[0])
        b = f(E[1:])
        a.extend(b)
        return a

En fait, j'ai adapté cela à partir d'un code de schéma de pratique que j'avais écrit il y a longtemps. 

Prendre plaisir!

0
inspectorG4dget

Tiré sans vergogne de ma propre réponse à une autre question .

Cette fonction

  • N'utilise pas isinstance, parce que c'est diabolique et empêche la dactylographie.
  • Utilise reduce récursivement. Il doit y avoir une réponse utilisant reduce.
  • Fonctionne avec des listes imbriquées arbitraires dont les éléments sont soit des listes imbriquées, soit des listes d'atomes non imbriquées, soit des atomes (soumis à une limite de récursivité).
  • Ne pas LBYL.
  • Mais pas avec les listes imbriquées qui contiennent des chaînes en tant qu'atomes.

Code ci-dessous:

def flattener(left, right):
    try:
        res = reduce(flattener, right, left)
    except TypeError:
        left.append(right)
        res = left
    return res


def flatten(seq):
    return reduce(flattener, seq, [])


>>> nested_list = [0, [1], [[[[2]]]],
                   [3, [], [4, 5]],
                   [6, [7, 8],
                    9, [[[]], 10,
                        []]],
                   11, [], [],
                   [12]]
>>> flatten(nested_list)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
0
Cong Ma