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

时间:2019-01-25 10:45:57

标签: python

我有一个Python列表列表,我想(尽快:非常重要...)在每个子列表中追加出现在嵌套列表中的时间。

我已经完成了一些pandas数据帧的操作,但这似乎很慢,我需要在非常大的范围内运行此行。 我完全愿意将可读性好的代码牺牲为高效的代码。

例如,我的嵌套列表在这里:

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

我需要拥有:

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

编辑

res中的顺序根本没有关系。

4 个答案:

答案 0 :(得分:10)

如果顺序无关紧要,您可以将collections.Counterextended iterable unpacking一起使用,作为@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 :(得分: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之前的插入顺序,请使用the OrderedCounter recipe

答案 2 :(得分: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]])

答案 3 :(得分: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]])