问题
I need to flatten all the levels of a multi-level list:
import itertools
pool = [[[[[0,2],[1,3]],[[3,2],[1,0]]],"PdPd","PrisonerDilemma"],
[[[[0,3],[1,2]],[[2,3],[1,0]]],"ShSh","StagHunt"],
[[[[1,2],[3,0]],[[3,2],[1,0]]],"ChCh","Chicken"],
[[[[2,1],[0,3]],[[3,1],[0,2]]],"BaBa","Battle"]]
def flat3 (pool):
for game in pool:
l = list(itertools.chain.from_iterable(game[0]))
print(l)
The result:
flat3 (pool)
[[0, 2], [1, 3], [3, 2], [1, 0]]
[[0, 3], [1, 2], [2, 3], [1, 0]]
[[1, 2], [3, 0], [3, 2], [1, 0]]
[[2, 1], [0, 3], [3, 1], [0, 2]]
So, the objective is to isolate and return the first level in each item, containing only the numbers, such as:
[[[[[0,2],[1,3]],[[3,2],[1,0]]],"PdPd","PrisonerDilemma"]
Then I need everything to be flattened to the same level, like:
[0,2,1,3,3,2,1,0]
I know there is a lot of material on this topic and I have found and tried many ways of doing this, however none seems to work with more than one level, I want to know if there is an efficient way to do this, without repeating the same command many times. Could anyone help me?
Thank you
回答1:
The first step, as usual, is to look at your data structure.
el = [
[
[[0,2],[1,3]],
[[3,2],[1,0]]
],
"PdPd",
"PrisonerDilemma"
]
This is each individual element in your structure. We'll ignore for the time being that this outermost structure almost certainly shouldn't be a list (it looks more like a tuple to me) and just focus on what we've got.
el[0] = [ [[0, 2], [1, 3]],
[[3, 2], [1, 0]] ]
el[1] = # a string
el[2] = # another string, we don't care about these
Now we've reduced it to a list of lists of LISTS of numbers. This one we can operate on.
def flatten(lst):
for el in lst:
if isinstance(el, list): # N.B. this only works for lists, not general
# collections e.g. sets, tuples, dicts, etc...
# recurse
yield from flatten(el)
else:
# generate
yield el
your result then being to apply this function to the first element of each item in the outermost list.
result = [flatten(sublst[0]) for sublst in big_list]
Note that this creates a list of generator objects, which need to be consumed to actually produce values. If you actually need the lists themselves for some reason, cast to list explicitly:
result = [list(flatten(sublst[0])) for sublst in big_list]
回答2:
def flat(pool):
res = []
for v in pool:
if isinstance(v, list):
res += flat(v)
else:
if isinstance(v, int):
res.append(v)
return res
demo
回答3:
Create a function which returns a flattened list of the numbers.
This function takes a list and looks at each item. If item is a number, add it to the return list. If it is a list, call the function recursively on this list and add the returned list to the return list of calling function. If it is a str
or something else, ignore the item.
回答4:
If your last output is all digits of every nested list then you can just fetch them using regular expression :
One line solution :
import re
pool = [[[[[0,2],[1,3]],[[3,2],[1,0]]],"PdPd","PrisonerDilemma"],
[[[[0,3],[1,2]],[[2,3],[1,0]]],"ShSh","StagHunt"],
[[[[1,2],[3,0]],[[3,2],[1,0]]],"ChCh","Chicken"],
[[[[2,1],[0,3]],[[3,1],[0,2]]],"BaBa","Battle"]]
pattern=r'\d+'
print([[int(i) for i in re.findall(pattern,str(i))] for i in pool ])
output:
[[0, 2, 1, 3, 3, 2, 1, 0], [0, 3, 1, 2, 2, 3, 1, 0], [1, 2, 3, 0, 3, 2, 1, 0], [2, 1, 0, 3, 3, 1, 0, 2]]
Detailed solution:
Above list comprehension is same as:
for i in pool:
nested_list=[]
for i in re.findall(pattern, str(i)):
nested_list.append(int(i))
print(nested_list)
来源:https://stackoverflow.com/questions/47983117/flattening-a-multilevel-list-of-lists-to-a-single-level