【问题标题】:How to get count dict of items but maintain the order in which they appear?如何获取项目的计数字典但保持它们出现的顺序?
【发布时间】:2014-07-07 23:49:44
【问题描述】:

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

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 方法,任何能产生正确结果的方法对我来说都可以。

【问题讨论】:

标签: python python-3.x dictionary counter ordereddictionary


【解决方案1】:

您可以使用recipe 使用collections.Countercollections.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)]))

【讨论】:

    【解决方案2】:

    在 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 中的 Counter 不显示它所维护的插入顺序;相反,__repr__sorts the return 从最常见到最不常见。

    但是您可以使用相同的 OrderedDict recipe 但只需使用 Python 3.6+ dict 代替:

    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})
    

    或者,由于 Counter 是 dict 的子类,它在 Python 3.6+ 中保持顺序,因此您可以通过在柜台上调用 .items() 或将柜台转回 dict 来避免使用 Counter 的 __repr__

    >>> c=Counter(words)
    

    该计数器的此演示文稿按最常见元素排序到最少,并使用 Counters __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}
    

    【讨论】:

      【解决方案3】:

      Python 3.6 中,字典是按插入顺序排列的,但这是一个实现细节。

      Python 3.7+ 中,插入顺序得到保证并且可以依赖。详情请见Are dictionaries ordered in Python 3.6+?

      因此,根据您的 Python 版本,您可能希望按原样使用Counter,而不是创建documentation 中描述的OrderedCounter 类。这是因为Counterdict 的子类,即issubclass(Counter, dict) 返回True,因此继承了dict 的插入排序行为。

      字符串表示

      值得注意的是 Counter 的字符串表示形式,在 repr 方法中定义,has not been updated 反映了 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
      

      【讨论】:

        【解决方案4】:

        在 cmets 中解释

        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]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-10-21
          • 2020-11-01
          • 1970-01-01
          • 2020-06-15
          • 2013-08-21
          • 2019-06-24
          • 1970-01-01
          相关资源
          最近更新 更多