计算嵌套列表中一个重复列表的出现次数

4

我有一个Python中的列表嵌套,现在需要找出每个子列表出现的次数。以下是一个示例:

from collections import Counter
list1 = [[ 1., 4., 2.5], [ 1., 2.66666667, 1.33333333], 
         [ 1., 2., 2.], [ 1., 2.66666667, 1.33333333], [ 1., 4., 2.5],
         [ 1., 2.66666667, 1.33333333]]   
c = Counter(x for x in iter(list1))
print c

如果列表的元素是可哈希的(例如 int),那么上面的代码可以正常工作,但在这种情况下它们是列表,因此会出错。

TypeError: unhashable type: 'list'

如何对这些列表进行计数,以便获得如下格式的结果:
[ 1., 2.66666667, 1.33333333], 3
[ 1., 4., 2.5], 2
[ 1., 2., 2.], 1

1
将它们转换为元组 - 它们是可哈希的。 - Maroun
3个回答

10

将列表转换为元组:

>>> c = Counter(tuple(x) for x in iter(list1))
>>> c
Counter({(1.0, 2.66666667, 1.33333333): 3, (1.0, 4.0, 2.5): 2, (1.0, 2.0, 2.0): 1})

记得对查找功能也执行同样的操作:

>>> c[tuple(list1[0])]
2

哇,这真是太简单了。只是为了确保计数器始终按照最高到最低频率的顺序返回值? - rambalachandran
@WanderingMind 不太确定你的意思。如果你想按照降序频率排序,使用 c.most_common() - tobias_k
你展示的结果具有从高到低值的频率。我想知道这是否是预期结果。看起来,你需要使用 most_common() 来获得这种行为。 - rambalachandran
1
@WanderingMind Counter 是由字典支持的,因此当您仅打印或迭代计数器时,它们被打印的顺序有点随机。如果您想按特定顺序获取它们,则必须使用 most_common - tobias_k
@tobias_k,有没有办法打印生成器对象,使其不会将“<generator object [function].<locals>.<genexpr> at 0x0000027AC384A...>”附加到它所指向的元组中的项上? - spacedustpi
显示剩余2条评论

2

计数器返回一个类似字典的对象,它的键必须是可哈希的。由于列表不可哈希,因此您可以使用map函数将其转换为tuple

>>> Counter(map(tuple, list1))
Counter({(1.0, 2.66666667, 1.33333333): 3, (1.0, 4.0, 2.5): 2, (1.0, 2.0, 2.0): 1})

请注意,使用map会比生成器表达式略微更快,因为通过将生成器表达式传递给Counter(),Python将自己从生成器函数中获取值,而使用内置函数map在执行时间方面具有更高的性能1
# Use generator expression
~ $ python -m timeit --setup "list1 = [[ 1., 4., 2.5], [ 1., 2.66666667, 1.33333333],[ 1., 2., 2.], [ 1., 2.66666667, 1.33333333], [ 1., 4., 2.5],[ 1., 2.66666667, 1.33333333]] ;from collections import Counter" "Counter(tuple(x) for x in iter(list1))"
100000 loops, best of 3: 9.86 usec per loop
# Use map
~ $ python -m timeit --setup "list1 = [[ 1., 4., 2.5], [ 1., 2.66666667, 1.33333333],[ 1., 2., 2.], [ 1., 2.66666667, 1.33333333], [ 1., 4., 2.5],[ 1., 2.66666667, 1.33333333]] ;from collections import Counter" "Counter(map(tuple, list1))"
100000 loops, best of 3: 7.92 usec per loop

来自PEP 0289 -- 生成器表达式

The semantics of a generator expression are equivalent to creating an anonymous generator function and calling it. For example:

g = (x**2 for x in range(10))
print g.next()

is equivalent to:

def __gen(exp):
    for x in exp:
        yield x**2
g = __gen(iter(range(10)))
print g.next()

请注意,由于生成器表达式在内存使用方面更好,如果您正在处理大量数据,则最好使用生成器表达式而不是map函数。


有没有类似 Python 的方式进行查找? - rambalachandran
@WanderingMind 你所说的lookup是什么意思? - Mazdak
如何知道特定子列表(例如list1[5])的频率? - rambalachandran
只需将 map(tuple, list1) 的结果放入一个新列表中,然后执行 Counter_object[new_list[5]] - Mazdak

1

试试这个

list1 = [[ 1., 4., 2.5], [ 1., 2.66666667, 1.33333333], 
         [ 1., 2., 2.], [ 1., 2.66666667, 1.33333333], [ 1., 4., 2.5],
         [ 1., 2.66666667, 1.33333333]]

counter = {}
for el in list1:
    el = str(el)     #This sorts your hashable part or use tuple(el)
    if el in counter:
        counter[el]+=1
    else:
        counter[el]=1

print(counter)

应输出。
{'[1.0, 2.0, 2.0]': 1, '[1.0, 2.66666667, 1.33333333]': 3, '[1.0, 4.0, 2.5]': 2}

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