[英]Pythonic way to generate a list of list
从以下输入中实现转换的最Python方式是什么:
input = [('a', 1), ('a', 10), ('b', 244), ('c', 31) , ('c',45)]
到所需的输出:
output = [[('a',1),('a',10)],[('c',31),('c',45)]]
我分组的地方列出了具有相同第一个元素的元组。
感觉到Python在一行上编写复杂事物方面具有强大的潜力(我是它的新手),所以我决定使用综合列表。 我最初的尝试是这样的:
output = [x for x in input if [k[0] for f in input].count(x[0])>1]
给我所有“伪”重复项的好列表:
output = [('a',1),('a',10),('c',31),('c',45)]
我进一步处理以获得我的结果。
我的问题是:有没有一种方法可以使用综合列表而不是两个(难看的)步骤在一行中实现此结果?
使用itertools
groupby
并列出列表。 这将为您提供一个简单的衬板:
from itertools import groupby
filter(lambda x: len(x)>1, [list(g) for i,g in groupby(input, key=lambda x: x[0])])
[[('a', 1), ('a', 10)], [('c', 31), ('c', 45)]]
使用1列清单理解:
>>> L=[('a', 1), ('a', 10), ('b', 244), ('c', 31) , ('c',45)]
>>> [list(filter(lambda x:x[0]==i, L)) for i in set(map(lambda x:x[0], L)) if len(list(filter(lambda x:x[0]==i, L)))>1]
[[('a', 1), ('a', 10)], [('c', 31), ('c', 45)]]
使用itertools.groupby
。 我的解决方案不是单一的,而是更具可读性。
import itertools
lists_in = [('a', 1), ('a', 10), ('b', 244), ('c', 31) , ('c',45)]
lists_out = list()
for name, group in itertools.groupby(lists_in, key=lambda x:x[0]):
l = list(group)
if len(l) == 2:
lists_out.extend(l)
print(lists_out)
# Output
[('a', 1), ('a', 10), ('c', 31), ('c', 45)]
以下内容没有错:
input = [('a', 1), ('a', 10), ('b', 244), ('c', 31) , ('c',45)]
d = {}
for i in input:
if i[0] in d:
d[i[0]].append(i)
else:
d[i[0]] = [i]
print([d[k] for k in d if len(d[k]) > 1])
别忘了,您必须在可读性和机敏性之间保持平衡。
以后的编辑 :实际上,我从其他答案中收集了其他解决方案,并测量了时间执行(200000个具有“ a'-'z”第一个元素的均匀分布的元组),请参见下文:
# 0.048532 s
def foo(input):
d = {}
for i in input:
if i[0] in d:
d[i[0]].append(i)
else:
d[i[0]] = [i]
return len(([d[k] for k in d if len(d[k]) > 1]))
# 1.9594 s
def foo2(input):
[list(filter(lambda x:x[0]==i, input)) for i in set(map(lambda x:x[0], input)) if len(list(filter(lambda x:x[0]==i, input)))>1]
# 0.209639 s
def foo3(input):
[filter(lambda x: len(x)>1, [list(g) for i,g in itertools.groupby(input, key=lambda x: x[0])])]
# 0.188625
def foo4(input):
lists = list()
for name, group in itertools.groupby(input, key=lambda x: x[0]):
l = list(group)
if len(l) == 2:
lists.extend(l)
# didn't even finish, >120 s
def foo5(input_list):
[[x for x in input_list if x[0]==a] for a in {x[0] for x in input_list if [k[0] for k in input].count(x[0])>1}]
因此,是的,更聪明的单行解决方案,但较慢且较难阅读的并不是真正的“最Python式”。
这是一种解决方案:
>>> input_list = [('a', 1), ('a', 10), ('b', 244), ('c', 31) , ('c',45)]
>>> [[x for x in input_list if x[0]==a] for a in {x[0] for x in input_list if [k[0] for k in input].count(x[0])>1}]
将打印
>>> [[('a', 1), ('a', 10)], [('c', 31), ('c', 45)]]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.