我正在尝试在Python中以单行表达式进行分组。我想建立一个dict
的组和组中的项目数:
{k: {'objects': list(g), 'count': len(list(g))}
for k,g in groupby(rows, key=lambda x: x['group_id'])}
但是g
是一个迭代器,不能与'count': len(list(g))
一起使用。
如何在一个行表达式中计数和重用g
?
答案 0 :(得分:4)
您不能多次在迭代器上调用list()
,否。您必须先存储结果。
根据可行性,您的选择是:
for
循环,然后将list()
的结果首先分配给一个单独的变量。groupby()
迭代器包装在将list()
应用于组对象的生成器表达式中。list()
调用,因此您可以将循环目标用作要构建的字典中两个键的变量。list()
调用结果分配给一个名称以供len()
重用之前,第一个应该是首选选项。可读性很重要!
result = {}
for group_id, group in groupby(rows, key=lambda x: x['group_id']):
objects = list(group)
result[group_id] = {'objects': objects, 'count': len(objects)}
使用生成器表达式可能是下一个最佳选择:
list_group = ((k, list(g)) for k, g in groupby(rows, key=lambda x: x['group_id']))
result = {k: {'objects': gl, 'count': len(gl)} for k, gl in list_group}
生成器表达式循环在for k, gl in list_group
迭代时并行执行。
第二个循环选项如下:
{
k: {'objects': gl, 'count': len(gl)}
for k, g in groupby(rows, key=lambda x: x['group_id'])
for gl in (list(g),)
}
由于此技巧令人惊讶且难以阅读,因此强烈建议您不要使用它。
在Python 3.8中,实现了PEP 572的您可以使用:
{
k: {'objects': gl := list(g), 'count': len(gl)}
for k, g in groupby(rows, key=lambda x: x['group_id'])
}
可以使用itertools.tee()
object将迭代器“加倍”,但这必须将整个列表分别缓存在内存中,使内存成本加倍,并且代码将变得不再可读(因为您必须使用类似的技巧然后将tee()
调用迭代器也存储在变量中!)。