与defaultdict结合使用时,计数器排序丢失了

时间:2018-10-23 22:59:29

标签: python python-3.x dictionary counter

我试图获取一个由(item_number, fruit)元组组成的列表,并计算每种水果在列表中出现的次数。使用collections.Counter很简单。我正在与此同时使用most_common()

我遇到的问题是试图显示与它们变得混乱的特定水果类型相对应的item_numbers列表。

这是我的示例代码:

#!/usr/bin/env python

from collections import Counter, defaultdict

mylist = [
            (1, 'peach'),
            (2, 'apple'),
            (3, 'orange'),
            (4, 'apple'),
            (5, 'banana'),
            (6, 'apple'),
            (7, 'orange'),
            (8, 'peach'),
            (9, 'apple'),
            (10, 'orange'),
            (11, 'plum'),
            ]

# FIRST, HANDLE JUST COUNTING THE ITEMS

normal_list = []

# append to a simple list
for item_number, fruit in mylist:
    normal_list.append(fruit)

# prints just the name of each fruit and how many times it appears
for fruit, count in Counter(normal_list).most_common(10):
    print(f'{fruit}\tCount: {count}')  

# NOW TRY TO INCLUDE THE LIST IF ITEM NUMBERS ALSO

mydefaultdict = defaultdict(list)

# append to the defaultdict
for item_number, fruit in mylist:
    mydefaultdict[fruit].append(item_number)

# prints each fruit, followed by count, and finally the list of IPs for each
for fruit, item_list in Counter(mydefaultdict).most_common(10):
    print(f'{fruit}\tCount: {len(item_list)}\tList: {item_list}')

我正在获得简单版本的预期输出:

apple   Count: 4
orange  Count: 3
peach   Count: 2
banana  Count: 1
plum    Count: 1

但是,当我尝试向其中添加item_number列表时,结果不再排序,当我使用的most_common()值小于水果品种总数时会造成严重破坏:

plum    Count: 1    List: [11]
banana  Count: 1    List: [5]
orange  Count: 3    List: [3, 7, 10]
apple   Count: 4    List: [2, 4, 6, 9]
peach   Count: 2    List: [1, 8]

我确定我可以在这里做一些不同的事情,但我不确定该怎么做。

2 个答案:

答案 0 :(得分:3)

Counter(mydefaultdict)并没有按照您的想法进行。您将defaultdict列表馈送到Counter,其目的是计算发生次数,而不是计算列表的长度。实际上,Counter对象的只是列表,而不是整数。 Counter不会抱怨,因为它是dict的子类,并且像dict一样可以用另一本字典初始化。

要按最长列表排序,可以将heapq.nlargest与自定义功能一起使用:

from heapq import nlargest

for fruit, item_list in nlargest(10, mydefaultdict.items(), key=lambda x: len(x[1])):
    print(f'{fruit}\tCount: {len(item_list)}\tList: {item_list}')

apple   Count: 4    List: [2, 4, 6, 9]
orange  Count: 3    List: [3, 7, 10]
peach   Count: 2    List: [1, 8]
banana  Count: 1    List: [5]
plum    Count: 1    List: [11]

答案 1 :(得分:3)

这部分很困难:

Counter(mydefaultdict)

您的对象mydefaultdict已使用 lists 作为值填充,但是Counter对象通常具有正整数作为值。这实际上不是错误,因为Counter是dict的子类,因此它将接受任何dict作为初始化参数。除非有问题:most_common不再返回理智的结果(以防您好奇,实际上是根据列表放置了lexicographical order)。

也许更清晰的是这样的:

most_common_fruits = sorted(mydefaultdict, key=lambda f: len(mydefaultdict[f]), reverse=True)
for fruit in most_common_fruits:
    item_list = mydefaultdict[fruit]
    ...

现在输出是这样的:

apple   Count: 4    List: [2, 4, 6, 9]
orange  Count: 3    List: [3, 7, 10]
peach   Count: 2    List: [1, 8]
banana  Count: 1    List: [5]
plum    Count: 1    List: [11]