2013-05-24 14 views
6

Sto facendo un gioco di cuore per il mio incarico, ma non so come ottenere ogni elemento in un elenco di lista:Come ottenere ogni elemento in un elenco di elenchi di elenchi?

>>>Cards = [[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C],["JH"]],[["7D"]]] 

e ciò che viene in mente è:

for values in cards: 
    for value in values: 

Ma penso di avere solo un elemento che ha 2 liste. Come calcolare quello che ha 3 e 1 lista nelle carte?

+3

Ho modificato il tuo codice per aggiungere un '' 'come mancante. Perché hai annullato quella modifica? –

+0

Avrai bisogno di qualche ricorsività per ottenere quello che vuoi in modo pulito – Maresh

+0

Hai tutte le carte a la stessa profondità? Quindi devi solo andare lì. –

risposta

15

Ti piace questa:

>>> Cards = [[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C"],["JH"]],["7D"]] 
>>> from compiler.ast import flatten 
>>> flatten(Cards) 
['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7D'] 

Come, Super Nacho sottolineato, il pacchetto compiler è deprecato. Questa è la fonte di flatten:

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 
+0

Brillante! Non sapevo che esistesse. – HennyH

+0

Non penso che intendessero usare quella funzione in questo modo, ma se funziona ... :). – Blubber

+1

Wow !!!! Molte grazie!! –

4

Se le carte sono annidati in maniera ingombrante:

>>> Cards = [[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C"],["JH"]],["7D"]] 
>>> def getCards(cardList,myCards=[]): #change this to myCards, and pass in a list to mutate this is just for demo 
     if isinstance(cardList,list): 
      for subList in cardList: 
       getCards(subList) 
     else: 
      myCards.append(cardList) 
     return myCards 
>>> getCards(Cards) 
['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7D'] 

Sarà recursivly passare attraverso la lista e trovare tutti gli elementi. Questi sono alcuni timeings ho eseguito confrontando le prestazioni del flattern metodologia prescelta per la mia:

>>> print(timeit.timeit(r'getCards([[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C"],["JH"]],["7D"]],[])',setup="from clas import getCards")) 
5.24880099297 
>>> timeit.timeit(r'flatten([[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C"],["JH"]],["7D"]])',setup="from compiler.ast import flatten") 
7.010887145996094 
5

leggermente oscura oneliner:

>>> [a for c in Cards for b in c for a in b] 
['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7', 'D'] 

si potrebbe desiderare di dare a, b e c nomi più descrittivi.

+0

sembra corretto per la parte iniziale. Ma il 7 ed è separato –

+2

@blubber il problema è che non sono nidificati uni-formalmente (che è un modo strano per memorizzare i dati di gioco ...) – HennyH

+0

Sì, lo vedo ora. Beh, non puoi usare questo, quindi funziona solo su liste formate regolarmente. – Blubber

2

L'elenco è una lista annidata incompleta, in modo da poter rendere primo rettangolare using the procedure explained here, per esempio, e poi appiattire la risultante numpy.ndarray.

I "se" di seguito non sarebbero necessari anche se l'ultimo elemento ['7D'] era [['7D']] (quindi anche le altre risposte funzionerebbero).

import numpy as np 
collector = np.zeros((3,3,3),dtype='|S20') 

for (i,j,k), v in np.ndenumerate(collector): 
    try: 
     if not isinstance(cards[i], str): 
      if not isinstance(cards[i][j], str): 
       collector[i,j,k] = cards[i][j][k] 
      else: 
       collector[i,j,0] = cards[i][j] 
     else: 
      collector[i,0,0] = cards[i] 
    except IndexError: 
     collector[i,j,k] = '' 

print collector[collector<>''].flatten() 
2

Utilizzando generatori, è possibile scrivere un applicazione molto più leggibile di flatten:

def flatten(l): 
    if isinstance(l, list): 
     for e1 in l: 
      for e2 in flatten(e1): 
       yield e2 
    else: 
     yield l 

Oppure, se si sta utilizzando Python 3.3, che ha aggiunto il yield from sintassi:

def flatten(l): 
    if isinstance(l, list): 
     for e in l: 
      yield from flatten(e) 
    else: 
     yield l 

Risultato:

>>> list(flatten([[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C"],["JH"]],[["7D"]]])) 
['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7D'] 
2

Usa 2 annidato itertools.chain per appiattire la lista:

In [32]: Cards 
Out[32]: [[['QS', '5H', 'AS'], ['2H', '8H'], ['7C']], [['9H', '5C'], ['JH']], ['7D']] 

In [33]: from itertools import chain 

In [34]: [k for k in chain.from_iterable([i for i in chain.from_iterable(Cards)])] 
Out[34]: ['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7', 'D'] 
2

Questa soluzione è molto robusto per qualsiasi tipo di liste annidate o tuple (per aggiungere altri tipi iterabili basta aggiungere più or isinstance(...) nel seguente codice.

E 'appena chiama ricorsivamente una funzione che si dispiega:

def unfold(lst): 
    output = [] 
    def _unfold(i): 
     if isinstance(i, list) or isinstance(i, tuple): 
      [_unfold(j) for j in i] 
     else: 
      output.append(i) 
    _unfold(lst) 
    return output 

print unfold(cards) 
#['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7D'] 
1

Utilizzando Flatten a list dal codice Rosetta si potrebbe fare:

>>> def flatten(lst): 
    return sum(([x] if not isinstance(x, list) else flatten(x) 
      for x in lst), []) 

>>> Cards = [[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C"],["JH"]],["7D"]] 
>>> flatten(Cards) 
['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7D'] 
>>> 

La soluzione si appiattisce solo liste annidate - non tuple o stringhe.

1
from itertools import chain, imap 

l= [[["QS","5H","AS"],["2H","8H"],["7C"]],[["9H","5C"],["JH"]],[["7D"]]] 

k = list(chain.from_iterable(imap(list, l))) 
m = list(chain.from_iterable(imap(list, k))) 

print m 

uscita: [ 'QS', '5H' 'come', '2H', '8H', '7C', '9H', '5C', 'JH', '7D']

Itertools è incredibile!

Problemi correlati