在嵌套列表中,计算相同子列表出现次数的更快方法是什么?

9
我有一个Python中的列表,我想尽可能快地向每个子列表中添加它出现在嵌套列表中的次数。我已经用一些pandas数据框架完成了这个任务,但这似乎非常慢,并且我需要在非常大的规模上运行这些代码。我完全愿意牺牲易读性以换取效率。例如,我的嵌套列表如下:
l = [[1, 3, 2], [1, 3, 2] ,[1, 3, 5]]

我需要有:

res = [[1, 3, 2, 2], [1, 3, 5, 1]]

编辑

res 中的顺序完全不重要。

4个回答

10

如果顺序不重要,您可以使用collections.Counter扩展迭代拆包的方式,作为@Chris_Rands解决方案的变体:

from collections import Counter

l = [[1, 3, 2], [1, 3, 2] ,[1, 3, 5]]

result = [[*t, count] for t, count in Counter(map(tuple, l)).items()]
print(result)

输出

[[1, 3, 5, 1], [1, 3, 2, 2]]

1
这是我的解决方案的一个合理(尽管大多数是外观)变体,当然假设使用Python 3。 - Chris_Rands

8

这是一种相当奇怪的输出需求,但当然是可能的。我建议使用 collections.Counter(),毫无疑问,其他人可能会提出不同的建议,使用 timeit 进行比较可以找到特定数据集最快的方法:

>>> from collections import Counter
>>> l = [[1, 3, 2], [1, 3, 2] ,[1, 3, 5]]
>>> [list(k) + [v] for k, v in Counter(map(tuple,l)).items()]
[[1, 3, 2, 2], [1, 3, 5, 1]]

在CPython 3.6 / Python 3.7之前保留插入顺序的注意事项,请使用有序计数器(OrderedCounter)配方


1
如果有选项使用numpy,你可以使用np.unique将轴设置为0并将return_counts设置为True,然后使用np.vstack连接唯一的行和计数:
l = np.array([[1, 3, 2], [1, 3, 2] ,[1, 3, 5]])
x, c = np.unique(l, axis=0, return_counts=True)
np.vstack([x.T,c]).T

array([[1, 3, 2, 2],
       [1, 3, 5, 1]])

0

由于您的项目是可变对象,而您必须将它们转换为不可变对象以用作映射键,因此一种优化的方法是使用以下方式的defaultdict()

In [5]: from collections import defaultdict

In [6]: d = defaultdict(int)

In [7]: for sub in l:
   ...:     d[tuple(sub)] += 1
   ...:     

In [8]: d
Out[8]: defaultdict(int, {(1, 3, 2): 2, (1, 3, 5): 1})

这将为您提供一个字典,其中子列表作为键,其计数作为值。

另一种方法是创建自己的字典对象:

 In [9]: class customdict(dict):
    ...:        
    ...:     def __getitem__(self, key):
    ...:         try:
    ...:             val = super(customdict, self).__getitem__(key)
    ...:         except KeyError:
    ...:             self[key] = [*key, 0]
    ...:         else:
    ...:             val[-1] += 1
    ...:             self[key] = val
    ...:             return val
    ...:         
    ...:    

 In [10]: m = customdict()

 In [11]: for sub in l:
     ...:     m[tuple(sub)]
     ...:     

 In [12]: 

 In [12]: m
 Out[12]: {(1, 3, 2): [1, 3, 2, 2], (1, 3, 5): [1, 3, 5, 1]}

 In [13]: m.values()
 Out[13]: dict_values([[1, 3, 2, 2], [1, 3, 5, 1]])

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