如何获取项目的计数字典,但保持它们出现的顺序?

10
例如,我需要计算一个单词在列表中出现的次数,不按频率排序,而是按单词出现的顺序,即插入顺序。
from collections import Counter

words = ['oranges', 'apples', 'apples', 'bananas', 'kiwis', 'kiwis', 'apples']

c = Counter(words)

print(c)

所以,不要返回这个: {'apples': 3, 'kiwis': 2, 'bananas': 1, 'oranges': 1}

我更希望得到的结果是: {'oranges': 1, 'apples': 3, 'bananas': 1, 'kiwis': 2}

而且我并不需要这个 Counter 方法,任何能够产生正确结果的方法都可以。


相关:创建有序计数器 - jpp
4个回答

13

从Python 3.6开始,dict会保持插入顺序。

因此,您可以这样做:

words = ["oranges", "apples", "apples", "bananas", "kiwis", "kiwis", "apples"]
counter={}
for w in words: counter[w]=counter.get(w, 0)+1
>>> counter
{'oranges': 1, 'apples': 3, 'bananas': 1, 'kiwis': 2}

很不幸,Python 3.6和3.7中的计数器并不会展示它所维护的插入顺序;相反,__repr__按照出现频率从高到低排序返回结果

但您可以使用同样的OrderedDict方法,只需使用Python 3.6+字典即可:

from collections import Counter

class OrderedCounter(Counter, dict):
    'Counter that remembers the order elements are first encountered'
    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, dict(self))

    def __reduce__(self):
        return self.__class__, (dict(self),)

>>> OrderedCounter(words)
OrderedCounter({'oranges': 1, 'apples': 3, 'bananas': 1, 'kiwis': 2})

或者,由于在Python 3.6+中Counter是维护顺序的字典子类,因此您可以通过在计数器上调用.items()或将计数器转换回dict来避免使用Counter的__repr__

>>> c=Counter(words)

该计数器的展示按照元素出现次数从多到少排序,并使用计数器的__repr__方法:

>>> c
Counter({'apples': 3, 'kiwis': 2, 'oranges': 1, 'bananas': 1})

这个演示文稿的排列顺序是按照出现或插入的顺序:

>>> c.items()
dict_items([('oranges', 1), ('apples', 3), ('bananas', 1), ('kiwis', 2)])

或者,

>>> dict(c)
{'oranges': 1, 'apples': 3, 'bananas': 1, 'kiwis': 2}

13
你可以使用利用collections.Counter和collections.OrderedDict的配方
from collections import Counter, OrderedDict

class OrderedCounter(Counter, OrderedDict):
    'Counter that remembers the order elements are first encountered'

    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

    def __reduce__(self):
        return self.__class__, (OrderedDict(self),)

words = ["oranges", "apples", "apples", "bananas", "kiwis", "kiwis", "apples"]
c = OrderedCounter(words)
print(c)
# OrderedCounter(OrderedDict([('oranges', 1), ('apples', 3), ('bananas', 1), ('kiwis', 2)]))

1
在Python 3.6中,字典是按插入顺序排列的,但这是一种实现细节。
在Python 3.7及以上版本中,插入顺序是有保证的,可以依赖它。有关更多详细信息,请参见Python 3.6+中的字典是否有序?
因此,根据您的Python版本,您可能希望只使用Counter,而不创建如文档中描述的OrderedCounter类。这是有效的,因为Counterdict的子类,即issubclass(Counter, dict)返回True,因此继承了dict的插入顺序行为。 字符串表示 值得注意的是,Counter 的字符串表示形式在 repr 方法中定义,未更新以反映3.6 / 3.7中的更改,即print(Counter(some_iterable))仍然按最大计数降序返回项目。您可以通过list(Counter(some_iterable))轻松返回插入顺序。
以下是演示行为的一些示例:
x = 'xyyxy'
print(Counter(x))         # Counter({'y': 3, 'x': 2}), i.e. most common first
print(list(Counter(x)))   # ['x', 'y'], i.e. insertion ordered
print(OrderedCounter(x))  # OC(OD([('x', 2), ('y', 3)])), i.e. insertion ordered

异常

如果您需要使用 OrderedCounter 提供的额外或重写的方法,则不应使用常规的 Counter。特别注意以下内容:

  1. OrderedDict 和因此 OrderedCounter 提供 popitemmove_to_end 方法。
  2. OrderedCounter 对象之间的相等性测试是有顺序敏感的,实现为 list(oc1.items()) == list(oc2.items())

例如,相等性测试将产生不同的结果:

Counter('xy') == Counter('yx')                # True
OrderedCounter('xy') == OrderedCounter('yx')  # False

0

在注释中解释

text_list = ['oranges', 'apples', 'apples', 'bananas', 'kiwis', 'kiwis', 'apples']


# create empty dictionary
freq_dict = {}
 
# loop through text and count words
for word in text_list:
    # set the default value to 0
    freq_dict.setdefault(word, 0)
    # increment the value by 1
    freq_dict[word] += 1
 
print(freq_dict )

{'oranges': 1, 'apples': 3, 'bananas': 1, 'kiwis': 2}

[Program finished]

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