Python 按属性将列表划分为子列表
我有以下分区功能:Python 按属性将列表划分为子列表,python,Python,我有以下分区功能: def group_by_name(data): names = set([entry.name for entry in data]) # detect all possible names # and now create a sublist for each possible name by_name = [[entry for entry in data if entry.name == name] for name in names]
def group_by_name(data):
names = set([entry.name for entry in data]) # detect all possible names
# and now create a sublist for each possible name
by_name = [[entry for entry in data if entry.name == name] for name in names]
return by_name
是否有一种更具python风格的方法来实现此功能
编辑
数据:
import random
class Data:
def __init__(self, name):
self.name = name
NAMES = [ 'jose', 'pedro', 'antonio', 'jesus', 'ricardo', 'anabel']
data = [Data(random.choice(NAMES)) for _ in range(100)]
您的方法是O(N*K)
,因为您迭代整个列表的次数与不同元素的次数相同。您可以使用以下模式在一次迭代中收集列表(O(N)
):
def group_by_name(data):
d = {}
for entry in data:
d.setdefault(entry.name, []).append(entry)
return list(d.values())
您还可以使用一些util使用一个O(N*logN)
1行程序:
from operator import attrgetter as ag
from itertools import groupby as gb
def group_by_name(data):
return [list(g) for _, g in gb(sorted(data, key=ag('name')), key=ag('name'))]
使用字典并在数据上循环,使用名称作为键,使用条目列表作为值。然后将每个键的值放入新构造的列表中,然后返回它。因为这是线性运行时,所以效率更高。一个可共享的
数据实例就更好了。此外,根据其类型可能会有一些技巧。@Kanak数据添加setdefault
将大大简化我的代码!我以前做过if key not in d
来初始化dicts…您也可以使用collections.defaultdict
来进一步提高可读性:d=defaultdict(list)
并且在循环中只需d[entry.name].append(entry)defaultdict
不是比dict
慢很多吗?如果您注意到一个很大的差异,我会感到惊讶。毕竟,它是dict的子类,在大多数操作中有效地使用相同的C代码。我要说的是,在几乎所有现实世界的情况下,可读性以及因此产生的生产力/可维护性都胜过性能。@NiklasMertsch“在一次迭代中收集列表”,这是正确的。返回值的列表构造函数不会迭代数据
,而是迭代d
(O(k)
,如果愿意的话),它会呈现整个过程O(n+k)
。