Python三重嵌套列表

12

我有一段代码,它给了我一个列表,其中包含一些三重嵌套的列表:

my_list = [[['item1','item2']], [['item3', 'item4']]]

我希望你能够将其改为:

my_list = [['item1','item2'], ['item3', 'item4']]

有什么建议吗?


4
my_list = list(map(lambda x :x[0], my_list)) - Vasif
2
有时候我在用Python写代码的时候会想念Ruby:[[['item1','item2']], [['item3', 'item4']]].flatten(1)。公平地说,这种情况也会发生在两个方向上。 - Eric Duminil
你的研究有什么发现,为什么其中的解决方案对你的情况不起作用? - jpmc26
当外层列表中有多个项目时,您希望发生什么情况? - Shadow
9个回答

24

使用列表推导式从每个子列表中选择单个子子列表:

>>> my_list = [item[0] for item in my_list]
[['item1', 'item2'], ['item3', 'item4']]

使用sum函数也可以将嵌套级别压缩到一起,但这会导致性能灾难,因为它的运行时间是二次方级别的:

In [5]: my_list = [[[i, i+1]] for i in range(0, 10000, 2)]

In [6]: %timeit sum(my_list, [])
78.6 ms ± 2.15 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [7]: %timeit [x[0] for x in my_list]
187 µs ± 3.05 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [8]: 78600/187
Out[8]: 420.32085561497325

对于一个长度为5000的my_list来说,这是一个420倍的减速,而这并不是一个非常长的列表。对于更长的列表来说,情况甚至更糟。


8
我也喜欢这个样子,但你不应该对超过非常少量的元素进行操作:https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/ - f5r5e5d
1
没有必要为微小的输入做时间测试,这几乎不反映大O性能。 - cs95
第二种方法会在item有多个元素时删除数据,并在item为空时引发错误。 - Eric Duminil
如果我提到楼主的问题,那就是主观的,不是吗? - akash karothiya
1
“sum”方法很糟糕,因为它没有任何好的理由而需要二次时间。 - user2357112
显示剩余2条评论

14

执行以下操作:

my_list = [j for i in my_list for j in i ]

12
可以用一个for循环实现:[i[0] for i in my_list] - srikavineehari
2
@srig:在我看来,双重列表推导更加简洁。它也不会删除数据,如果i有多个元素,并且如果i为空,也不会引发错误。 - Eric Duminil
@EricDuminil,我也有同样的想法,但是我按照OP的输入list去做了 :) - srikavineehari

13

一个简单但高效的方法是使用itertools.chain.from_iterable将您的三层嵌套列表展开:

>>> import itertools
>>> my_list = [[['item1','item2']],[['item3','item4']]]
>>> my_list = list(itertools.chain.from_iterable(my_list))
>>> my_list
[['item1', 'item2'], ['item3', 'item4']]

对于一个长度为n的列表,时间复杂度为O(n)


6

my_list = list(map(lambda x :x[0], my_list))


6
my_list = [[['item1','item2']],[['item3', 'item4']]]

使用列表推导式的一行代码

my_list = [sub[0] for sub in my_list]

你也可以原地更改 my_list

my_list = [[['item1','item2']],[['item3', 'item4']]]

for i, sub in enumerate(my_list):
    my_list[i] = sub[0]

>>> my_list
[['item1', 'item2'], ['item3', 'item4']]
>>> 

1
使用 mapoperator.itemgetter
map(operator.itemgetter(0), my_list)

在Python 3中,它返回一个生成器。如果你需要一个list,请将生成器包装在list(...)中。

0

如果你想要快速解决问题,这很简单 -

for i in range(len(my_list)):
    my_list[i]=my_list[i][0]

没有分号没问题,但为什么要删除列呢? - bouletta

0

Python3

[[x], [y]] = my_list
print([x , y])

[['item1', 'item2'], ['item3', 'item4']]

3
尽管这段代码可能解决问题,但包括解释真的有助于提高您帖子的质量。请记住,您正在为未来的读者回答问题,而这些人可能不知道您提出代码建议的原因。 - Isma

0

一个快速修复,只要您具有嵌套列表的类似结构,下面的递归函数(或其他情况下的类似函数)就可以处理任何级别的嵌套。没有测量性能,但与其他解决方案相比,它将更少。使用之前请进行充分测试。在Python 2.7中。

def f(x):
    if hasattr(x[0], '__iter__'):
        return f(x[0])
    else:
        return x

>>> my_list = [[['item1','item2']], [['item3', 'item4']]]
>>> [f(elem) for elem in my_list]
[['item1', 'item2'], ['item3', 'item4']]
>>> my_list = [[[['item1','item2']]], [['item3', 'item4']],[[[['item5', 'item6']]]]]
>>> [f(elem) for elem in my_list]
[['item1', 'item2'], ['item3', 'item4'], ['item5', 'item6']]

在Python 2中,hasattr()检查将跳过字符串。其他测试,如iter(),可能会将字符串视为可迭代的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接