2013-06-27 18 views
9

Sto cercando di appiattire un elenco usando la comprensione degli elenchi in python. La mia lista è un po 'comeappiattisce l'elenco delle liste attraverso la comprensione degli elenchi

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

solo per la stampa poi singola voce in questa lista di lista che ho scritto questo codice

def flat(listoflist): 
    for item in listoflist: 
      if type(item) != list: 
        print item 
      else: 
        for num in item: 
          print num 
>>> flat(list1) 
1 
2 
3 
4 
5 
6 
7 
8 

Poi ho usato la stessa logica di appiattire la mia lista attraverso di lista sto ottenendo il seguente errore

list2 = [item if type(item) != list else num for num in item for item in list1] 
    Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    TypeError: 'int' object is not iterable 

Come si appiattisce questo tipo di elenco di elenchi utilizzando la comprensione di elenchi?

risposta

6
>>> from collections import Iterable 
>>> from itertools import chain 

One-liner:

>>> list(chain.from_iterable(item if isinstance(item,Iterable) and 
        not isinstance(item, basestring) else [item] for item in lis)) 
[1, 2, 3, 4, 5, 6, 7, 8] 

Una versione leggibile:

>>> def func(x):           #use `str` in py3.x 
...  if isinstance(x, Iterable) and not isinstance(x, basestring): 
...   return x 
...  return [x] 
... 
>>> list(chain.from_iterable(func(x) for x in lis)) 
[1, 2, 3, 4, 5, 6, 7, 8] 
#works for strings as well 
>>> lis = [[1, 2, 3], [4, 5, 6], 7, 8, "foobar"] 
>>> list(chain.from_iterable(func(x) for x in lis))                 
[1, 2, 3, 4, 5, 6, 7, 8, 'foobar'] 

Utilizzando lista annidata di comprensione: (sta per essere lento rispetto a itertools.chain):

>>> [ele for item in (func(x) for x in lis) for ele in item] 
[1, 2, 3, 4, 5, 6, 7, 8, 'foobar'] 
+1

Questo è ottimo per il richiedente che usa 2.x, ma vale la pena notare che gli utenti 3.x dovrebbero usare 'str' invece di 'basestring'. –

+0

@Ashwini Cosa si dovrebbe fare se i miei elementi sono di tipo dict invece di intero? –

+0

@AnuragSharma piccolo esempio? –

3

Si sta tentando di ripetere un numero, che non è possibile fare (quindi l'errore).

Se stai usando python 2.7:

>>> from compiler.ast import flatten 
>>> flatten(l) 
[1, 2, 3, 4, 5, 6, 7, 8] 

Ma fai notare che il modulo è ormai obsoleto e non esiste più in Python 3

+1

Le check list di tipo non sono una buona idea. Lo rende molto meno flessibile. –

+1

se 'l' è' [[1, 2, 3], [4, 5, 6], 7, 888] ', la prima soluzione restituisce' [1, 2, 3, 4, 5, 6, 7, 8, 8, 8] '. – falsetru

+0

Rimosso il primo bit, ma è un peccato che la mia altra soluzione non funzioni in python 3 – TerryA

3

Una soluzione alternativa utilizzando un generatore:

import collections 

def flatten(iterable): 
    for item in iterable: 
     if isinstance(item, collections.Iterable) and not isinstance(item, str): # `basestring` < 3.x 
      yield from item # `for subitem in item: yield item` < 3.3 
     else: 
      yield item 

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

+1 Non si sa mai dell'istruzione 'yield from'. –

3

Nessuno ha dato la solita risposta:

def flat(l): 
    return [y for x in l for y in x] 

Ci sono i duplicati di questa domanda intorno a StackOverflo w.

+1

Il tuo codice non funziona per l'elenco fornito dall'OP poiché il suo elenco include oggetti non iterabili, ovvero interi. Il tuo codice funziona comunque se ogni elemento nell'elenco è un oggetto iterabile. Vedere il mio commento qui sotto. – JDG

+1

Grazie per avermelo fatto notare - Avrò davvero bisogno di trovare un momento per scherzare con quello e venire a fare i conti ... – GreenAsJade

Problemi correlati