简体   繁体   中英

How to get every element in a list of list of lists?

I'm making a heart game for my assignment but I don't know how to get every element in a list of list:

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

and what comes to my mind is :

for values in cards:
    for value in values:

But I think I just got element that has 2 list. How to calculate the one that has 3 and 1 list in the cards?

Like this:

>>> 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']

As, nacholibre pointed out, the compiler package is deprecated. This is the source of 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

Slightly obscure 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']

You might want to give a, b and c more descriptive names.

If your cards are nested in a unwieldy way:

>>> 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']

Will recursivly go through the list and find all the elements. These are some timeings I've run comparing performance of the selected flattern method to mine:

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

Your list is an incomplete nested list, so you can first make it rectangular, using the procedure explained here , for example, and then flatten the resulting numpy.ndarray .

The "ifs" below wouldn't be necessary as well if the last element ['7D'] was [['7D']] (then the other answers would also work).

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()

Using generators, it's possible to write a much more readable implementation of flatten :

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

Or, if you're using Python 3.3, which added the yield from syntax:

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

Result:

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

Use 2 nested itertools.chain to flatten the list:

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']

This solution is very robust for any kind of nested lists or tuples (to add other iterable types just add more or isinstance(...) in the code below.

It just calls recursively a function that unfolds itself:

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']

Using Flatten a list from Rosetta Code you could do:

>>> 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']
>>> 

The solution only flattens nested lists - not tuples or strings.

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

output: ['QS', '5H', 'AS', '2H', '8H', '7C', '9H', '5C', 'JH', '7D']

Itertools is amazing!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM