Python3 collections模塊使用詳解

python

簡(jiǎn)介

collections包含了一些特殊的容器,針對(duì)Python內(nèi)置的容器,例如list、dict、set和tuple,提供了另一種選擇;

namedtuple,可以創(chuàng)建包含名稱的tuple;

deque,類似于list的容器,可以快速的在隊(duì)列頭部和尾部添加、刪除元素;

Counter,dict的子類,計(jì)算可hash的對(duì)象;

OrderedDict,dict的子類,可以記住元素的添加順序;

defaultdict,dict的子類,可以調(diào)用提供默認(rèn)值的函數(shù);

模塊使用

Counter

counter可以支持方便、快速的計(jì)數(shù),例如,

from collections import *

cnt = Counter()
wordList = ["a","b","c","c","a","a"]
for word in wordList:
    cnt[word] += 1
print(cnt)
#輸出
Counter({'a': 3, 'c': 2, 'b': 1})

對(duì)可迭代的對(duì)象進(jìn)行計(jì)數(shù)或者從另一個(gè)映射(counter)進(jìn)行初始化,

>>> c = Counter()#一個(gè)新的,空的counter
>>> c
Counter()
>>> c = Counter("gallahad")#從可迭代的字符串初始化counter
>>> c
Counter({'a': 3, 'l': 2, 'h': 1, 'g': 1, 'd': 1})
>>> c = Counter({'red':4,'blue':2})#從映射初始化counter
>>> c
Counter({'red': 4, 'blue': 2})
>>> c = Counter(cats = 4,dogs = 8)#從args初始化counter
>>> c
Counter({'dogs': 8, 'cats': 4})

Counter對(duì)象類似于字典,如果某個(gè)項(xiàng)缺失,會(huì)返回0,而不是報(bào)出KeyError;

>>> c = Counter(['eggs','ham'])
>>> c['bacon']#沒有'bacon'
0
>>> c['eggs']#有'eggs'
1

將一個(gè)元素的數(shù)目設(shè)置為0,并不能將它從counter中刪除,使用del可以將這個(gè)元素刪除;

>>> c
Counter({'eggs': 1, 'ham': 1})
>>> c['eggs'] = 0
>>> c
Counter({'ham': 1, 'eggs': 0})#'eggs'依然存在
>>> del c['eggs']
>>> c
Counter({'ham': 1})#'eggs'不存在  

Counter對(duì)象支持以下三個(gè)字典不支持的方法,elements(),most_common(),subtract()

element(),返回一個(gè)迭代器,每個(gè)元素重復(fù)的次數(shù)為它的數(shù)目,順序是任意的順序,如果一個(gè)元素的數(shù)目少于1,那么elements()就會(huì)忽略它;

>>> c = Counter(a=2,b=4,c=0,d=-2,e = 1)
>>> c
Counter({'b': 4, 'a': 2, 'e': 1, 'c': 0, 'd': -2})
>>> list(c.elements())
['a', 'a', 'b', 'b', 'b', 'b', 'e']

most_common(),返回一個(gè)列表,包含counter中n個(gè)最大數(shù)目的元素,如果忽略n或者為None,most_common()將會(huì)返回counter中的所有元素,元素有著相同數(shù)目的將會(huì)以任意順序排列;

>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
>>> Counter('abracadabra').most_common()
[('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]
>>> Counter('abracadabra').most_common(None)
[('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]

subtract(),從一個(gè)可迭代對(duì)象中或者另一個(gè)映射(或counter)中,元素相減,類似于dict.update(),但是subtracts 數(shù)目而不是替換它們,輸入和輸出都有可能為0或者為負(fù);

>>> c = Counter(a=4,b=2,c=0,d=-2)
>>> d = Counter(a=1,b=2,c=-3,d=4)
>>> c.subtract(d)
>>> c
Counter({'a': 3, 'c': 3, 'b': 0, 'd': -6})

update(),從一個(gè)可迭代對(duì)象中或者另一個(gè)映射(或counter)中所有元素相加,類似于dict.upodate,是數(shù)目相加而非替換它們,另外,可迭代對(duì)象是一個(gè)元素序列,而非(key,value)對(duì)構(gòu)成的序列;

>>> c
Counter({'a': 4, 'b': 2, 'c': 0, 'd': -2})
>>> d
Counter({'d': 4, 'b': 2, 'a': 1, 'c': -3})
>>> c.update(d)
>>> c
Counter({'a': 5, 'b': 4, 'd': 2, 'c': -3})

Counter對(duì)象常見的操作,

>>> c
Counter({'a': 5, 'b': 4, 'd': 2, 'c': -3})
>>> sum(c.values())# 統(tǒng)計(jì)所有的數(shù)目
>>> list(c)# 列出所有唯一的元素
['a', 'c', 'b', 'd']
>>> set(c)# 轉(zhuǎn)換為set
set(['a', 'c', 'b', 'd'])
>>> dict(c)# 轉(zhuǎn)換為常規(guī)的dict
{'a': 5, 'c': -3, 'b': 4, 'd': 2}
>>> c.items()# 轉(zhuǎn)換為(elem,cnt)對(duì)構(gòu)成的列表
[('a', 5), ('c', -3), ('b', 4), ('d', 2)]
>>> c.most_common()[:-4:-1]# 輸出n個(gè)數(shù)目最小元素
[('c', -3), ('d', 2), ('b', 4)]
>>> c += Counter()# 刪除數(shù)目為0和為負(fù)的元素
>>> c
Counter({'a': 5, 'b': 4, 'd': 2})
>>> Counter(dict(c.items()))# 從(elem,cnt)對(duì)構(gòu)成的列表轉(zhuǎn)換為counter
Counter({'a': 5, 'b': 4, 'd': 2})
>>> c.clear()# 清空counter
>>> c
Counter()

在Counter對(duì)象進(jìn)行數(shù)學(xué)操作,得多集合(counter中元素?cái)?shù)目大于0)加法和減法操作,是相加或者相減對(duì)應(yīng)元素的數(shù)目;交集和并集返回對(duì)應(yīng)數(shù)目的最小值和最大值;每個(gè)操作均接受有符號(hào)的數(shù)目,但是輸出并不包含數(shù)目為0或者為負(fù)的元素;

>>> c = Counter(a=3,b=1,c=-2)
>>> d = Counter(a=1,b=2,c=4)
>>> c+d#求和
Counter({'a': 4, 'b': 3, 'c': 2})
>>> c-d#求差
Counter({'a': 2})
>>> c & d#求交集
Counter({'a': 1, 'b': 1})
>>> c | d#求并集
Counter({'c': 4, 'a': 3, 'b': 2})

deque

deque是棧和隊(duì)列的一種廣義實(shí)現(xiàn),deque是"double-end queue"的簡(jiǎn)稱;deque支持線程安全、有效內(nèi)存地以近似O(1)的性能在deque的兩端插入和刪除元素,盡管list也支持相似的操作,但是它主要在固定長(zhǎng)度操作上的優(yōu)化,從而在pop(0)和insert(0,v)(會(huì)改變數(shù)據(jù)的位置和大?。┥嫌蠴(n)的時(shí)間復(fù)雜度。

deque支持如下方法,

append(x), 將x添加到deque的右側(cè);

appendleft(x), 將x添加到deque的左側(cè);

clear(), 將deque中的元素全部刪除,最后長(zhǎng)度為0;

count(x), 返回deque中元素等于x的個(gè)數(shù);

extend(iterable), 將可迭代變量iterable中的元素添加至deque的右側(cè);

extendleft(iterable), 將變量iterable中的元素添加至deque的左側(cè),往左側(cè)添加序列的順序與可迭代變量iterable中的元素相反;

pop(), 移除和返回deque中最右側(cè)的元素,如果沒有元素,將會(huì)報(bào)出IndexError;

popleft(), 移除和返回deque中最左側(cè)的元素,如果沒有元素,將會(huì)報(bào)出IndexError;

remove(value), 移除第一次出現(xiàn)的value,如果沒有找到,報(bào)出ValueError;

reverse(), 反轉(zhuǎn)deque中的元素,并返回None;

rotate(n), 從右側(cè)反轉(zhuǎn)n步,如果n為負(fù)數(shù),則從左側(cè)反轉(zhuǎn),d.rotate(1)等于d.appendleft(d.pop());

maxlen, 只讀的屬性,deque的最大長(zhǎng)度,如果無解,就返回None;

除了以上的方法之外,deque還支持迭代、序列化、len(d)、reversed(d)、copy.copy(d)、copy.deepcopy(d),通過in操作符進(jìn)行成員測(cè)試和下標(biāo)索引,索引的時(shí)間復(fù)雜度是在兩端是O(1),在中間是O(n),為了快速獲取,可以使用list代替。

>>> from collections import deque
>>> d = deque('ghi')# 新建一個(gè)deque,有三個(gè)元素
>>> for ele in d:# 遍歷deque
...     print ele.upper()
...     
... 
G
H
I
>>> d.append('j')# deque右側(cè)添加一個(gè)元素
>>> d.appendleft('f')# deque左側(cè)添加一個(gè)元素
>>> d# 打印deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop()# 返回和移除最右側(cè)元素
'j'
>>> d.popleft()# 返回和移除最左側(cè)元素
'f'
>>> list(d)# 以列表形式展示出deque的內(nèi)容
['g', 'h', 'i']
>>> d[0]# 獲取最左側(cè)的元素
'g'
>>> d[-1]# 獲取最右側(cè)的元素
'i'
>>> list(reversed(d))# 以列表形式展示出倒序的deque的內(nèi)容
['i', 'h', 'g']
>>> 'h' in d# 在deque中搜索
True
>>> d.extend('jkl')# 一次添加多個(gè)元素
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)# 往右側(cè)翻轉(zhuǎn)
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)# 往左側(cè)翻轉(zhuǎn)
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d))# 以逆序新建一個(gè)deque
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()# 清空deque
>>> d.pop()# 不能在空的deque上pop
Traceback (most recent call last):
  File "<input>", line 1, in <module>
IndexError: pop from an empty deque
>>> d.extendleft('abc')# 以輸入的逆序向左擴(kuò)展
>>> d
deque(['c', 'b', 'a'])

其他應(yīng)用:

  • 限定長(zhǎng)度的deque提供了Unix中tail命令相似的功能;

    from collections import deque
    
    def tail(filename,n = 10):
        "Return the last n lines of a file"
        return deque(open(filename),n)
    
    print (tail("temp.txt",10))
    
  • 使用deque維護(hù)一個(gè)序列(右側(cè)添加元素,左側(cè)刪除元素)中窗口的平均值;

    from collections import deque
    import itertools
    
    def moving_average(iterable,n = 3):
        it = iter(iterable)
        d = deque(itertools.islice(it,n-1))
        # 第一次只有兩個(gè)元素,再右移的過程中,需要先刪除最左端的元素,因此現(xiàn)在最左端加入0
        d.appendleft(0)
        s = sum(d)
        for ele in it:
            # 刪除最左端的元素,再加上新元素
            s += ele - d.popleft()
            # 右端添加新元素
            d.append(ele)
            yield s / float(n)
    
    array = [40,30,50,46,39,44]
    for ele in moving_average(array,n=3):
        print (ele)
    
  • rotate()方法提供了一種實(shí)現(xiàn)deque切片和刪除的方式,例如,del d[n]依賴于rotate方法的純Python實(shí)現(xiàn),如下,

    from collections import deque
    
    def delete_nth(d,n):
        # 將前n個(gè)元素翻轉(zhuǎn)到右側(cè)
        d.rotate(-n)
        # 刪除第n個(gè)元素
        d.popleft()
        # 再將后n個(gè)元素翻轉(zhuǎn)到左側(cè)
        d.rotate(n)
    
    d = deque("abcdefg")
    delete_nth(d,n = 3)
    print (d)
    
  • slice依賴于rotate方法的純Python實(shí)現(xiàn),如下,

    from collections import deque
    
    def slice(d,m,n):
        # 先將前面m個(gè)元素翻轉(zhuǎn)到右側(cè)
        d.rotate(-m)
        i = m
        sliceList = []
        # 依次將[m,n]區(qū)間內(nèi)的元素出棧
        while i < n:
            item = d.popleft()
            sliceList.append(item)
            i+=1
        # 再將出棧的元素?cái)U(kuò)展到deque右側(cè)
        d.extend(sliceList)
        # 再將后面n個(gè)元素翻轉(zhuǎn)到左側(cè)
        d.rotate(n)
        return sliceList
    
    d = deque("abcdefg")
    print slice(d,1,5)
    

defaultdict

defaultdict是內(nèi)置數(shù)據(jù)類型dict的一個(gè)子類,基本功能與dict一樣,只是重寫了一個(gè)方法missing(key)和增加了一個(gè)可寫的對(duì)象變量default_factory。

>>> dir(defaultdict)
['__class__', '__cmp__', '__contains__', '__copy__', '__delattr__', '__delitem__
', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__
', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__',
'__missing__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '
__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear
', 'copy', 'default_factory', 'fromkeys', 'get', 'has_key', 'items', 'iteritems'
, 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'v
alues', 'viewitems', 'viewkeys', 'viewvalues']
>>> dir(dict)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__'
, '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
 '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '_
_new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__'
, '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get
', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'po
pitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

missing(key)

  • 如果default_factory屬性為None,就報(bào)出以key作為遍歷的KeyError異常;
  • 如果default_factory不為None,就會(huì)向給定的key提供一個(gè)默認(rèn)值,這個(gè)值插入到詞典中,并返回;
  • 如果調(diào)用default_factory報(bào)出異常,這個(gè)異常在傳播時(shí)不會(huì)改變;
  • 這個(gè)方法是當(dāng)要求的key不存在時(shí),dict類中的getitem()方法所調(diào)用,無論它返回或者報(bào)出什么,最終返回或報(bào)出給getitem();
  • 只有getitem()才能調(diào)用missing(),這意味著,如果get()起作用,如普通的詞典,將會(huì)返回None作為默認(rèn)值,而不是使用default_factory;

default_factory, 這個(gè)屬性用于missing()方法,使用構(gòu)造器中的第一個(gè)參數(shù)初始化;

使用list作為default_factory,很容易將一個(gè)key-value的序列轉(zhuǎn)換為一個(gè)關(guān)于list的詞典;

>>> from collections import *
>>> s = [('yellow',1),('blue',2),('yellow',3),('blue',4),('red',5)]
>>> d = defaultdict(list)
>>> for k,v in s: d[k].append(v)
... 
>>> d.items()
[('blue', [2, 4]), ('red', [5]), ('yellow', [1, 3])]

當(dāng)每一個(gè)key第一次遇到時(shí),還沒有準(zhǔn)備映射,首先會(huì)使用default_factory函數(shù)自動(dòng)創(chuàng)建一個(gè)空的list,list.append()操作將value添加至新的list中,當(dāng)key再次遇到時(shí),通過查表,返回對(duì)應(yīng)這個(gè)key的list,list.append()會(huì)將新的value添加至list,這個(gè)技術(shù)要比dict.setdefault()要簡(jiǎn)單和快速。

>>> e = {}
>>> for k,v in s: e.setdefault(k,[]).append(v)
... 
>>> e.items()
[('blue', [2, 4]), ('red', [5]), ('yellow', [1, 3])]

設(shè)置default_factory為int,使得defaultdict可以用于計(jì)數(shù),

>>> s = "mississippi"
>>> d = defaultdict(int)
>>> for k in s: d[k]+=1
... 
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]

當(dāng)一個(gè)字母第一次遇到,默認(rèn)從default_factory中調(diào)用int()用于提供一個(gè)默認(rèn)為0的計(jì)數(shù),遞增操作會(huì)增加每個(gè)字母的計(jì)數(shù)。

函數(shù)int()經(jīng)常返回0,是常量函數(shù)的一種特例。一種更快和更靈活的創(chuàng)建常量函數(shù)的方式是使用itertools.repeat(),可以提供任意常量值(不僅僅是0),

>>> import itertools
>>> def constant_factory(value):
...     return itertools.repeat(value).next
... 
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name = "John",action = "ran")
>>> "%(name)s %(action)s to %(object)s"%d
'John ran to <missing>'

將default_factory設(shè)置為set,使得defaultdict可以建立一個(gè)關(guān)于set的詞典,

>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue',
4)]
>>> d = defaultdict(set)
>>> for k,v in s:d[k].add(v)
... 
>>> d.items()
[('blue', set([2, 4])), ('red', set([1, 3]))]

namedtuple

命名的元組,意味給元組中的每個(gè)位置賦予含義,意味著代碼可讀性更強(qiáng),namedtuple可以在任何常規(guī)元素使用的地方使用,而且它可以通過名稱來獲取字段信息而不僅僅是通過位置索引。

>>> from collections import *
>>> Point = namedtuple('Point',['x','y'],verbose = True)
class Point(tuple):
    'Point(x, y)'

    __slots__ = ()

    _fields = ('x', 'y')

    def __new__(_cls, x, y):
        'Create new instance of Point(x, y)'
        return _tuple.__new__(_cls, (x, y))

    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new Point object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != 2:
            raise TypeError('Expected 2 arguments, got %d' % len(result))
        return result

    def __repr__(self):
        'Return a nicely formatted representation string'
        return 'Point(x=%r, y=%r)' % self

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values'
        return OrderedDict(zip(self._fields, self))

    def _replace(_self, **kwds):
        'Return a new Point object replacing specified fields with new values'
        result = _self._make(map(kwds.pop, ('x', 'y'), _self))
        if kwds:
            raise ValueError('Got unexpected field names: %r' % kwds.keys())
        return result

    def __getnewargs__(self):
        'Return self as a plain tuple.  Used by copy and pickle.'
        return tuple(self)

    __dict__ = _property(_asdict)

    def __getstate__(self):
        'Exclude the OrderedDict from pickling'
        pass

    x = _property(_itemgetter(0), doc='Alias for field number 0')

    y = _property(_itemgetter(1), doc='Alias for field number 1')
>>> p = Point(11,y = 22) # 實(shí)例化一個(gè)對(duì)象,可以使用位置或者關(guān)鍵字
>>> p[0] + p[1] # 通過索引訪問元組中的元素
>>> x,y = p # 分開,類似于常規(guī)的元組
>>> x,y
(11, 22)
>>> p.x + p.y # 通過名稱訪問元素
>>> p # 可讀的__repr__,通過name = value風(fēng)格
Point(x=11, y=22)

namedtuple在給csv或者sqlite3返回的元組附上名稱特別有用,

from collections import *
import csv

EmployeeRecord = namedtuple('EmployeeRecord','name, age, title, department, paygrade')
for emp in map(EmployeeRecord._make,csv.reader(open("employee.csv","rb"))):
    print (emp.name,emp.title)

# import sqlite3
# conn = sqlite3.connect('/companydata')
# cursor = conn.cursor()
# cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
# for emp in map(EmployeeRecord._make, cursor.fetchall()):
#     print emp.name, emp.title
#輸出
Jim RD
Tom Manager

除了從tuples繼承的方法之外,namedtuple還支持三種方法和一個(gè)屬性,為了避免和名稱沖突,這些方法和屬性以下劃線開始。

somenamedtuple._make(), 從已有的序列或者可迭代的對(duì)象中創(chuàng)建一個(gè)新的對(duì)象;

>>> Point = namedtuple('Point', ['x', 'y'])
>>> t = [33,44]
>>> Point._make(t)
Point(x=33, y=44)

somenamedtuple._asdict(), 返回一個(gè)OrderDict,由名稱到對(duì)應(yīng)值建立的映射;

>>> p = Point(x = 11,y = 22)
>>> p
Point(x=11, y=22)
>>> pDict = p._asdict()
>>> pDict
OrderedDict([('x', 11), ('y', 22)])

somenamedtuple._replace(), 返回一個(gè)新的namedtuple對(duì)象,用新值替換指定名稱中的值;

>>> p2 = p._replace(x = 33)
>>> p2
Point(x=33, y=22)

somenamedtuple._fields, 以字符串構(gòu)成的元組的形式返回namedtuple中的名稱,在自省或者基于一個(gè)已經(jīng)存在的namedtuple中創(chuàng)建新的namedtuple時(shí),非常有用;

>>> p._fields
('x', 'y')
>>> Color = namedtuple('Color',"red green blu")
>>> Pixel = namedtuple('Pixel',Point._fields + Color._fields)
>>> Pixel(11,22,128,255,0)
Pixel(x=11, y=22, red=128, green=255, blu=0)

當(dāng)名稱存儲(chǔ)在字符串中,可以使用getattr()函數(shù)進(jìn)行檢索,

>>> getattr(p,'x')
11

使用**操作符,可以將一個(gè)字典轉(zhuǎn)換成namedtuple,

>>> d  = {'x':11,'y':22}
>>> Point(**d)
Point(x=11, y=22)

由于namedtuple也是Python中的一個(gè)類,因此在子類中,它很容易添加或者修改一些功能,如下是添加一個(gè)可計(jì)算名稱和固定長(zhǎng)度的輸出格式;子類中的slots是一個(gè)空的元組,可以通過避免詞典實(shí)例的創(chuàng)建來節(jié)約內(nèi)存;

class Point(namedtuple('Point','x y')):
    __slots__ = ()
    @property
    def hypot(self):
        return (self.x ** 2 + self.y**2) ** 0.5
    def __str__(self):
        return "Point:x = %6.3f  y = %6.3f  hypot = %6.3f" %(self.x,self.y,self.hypot)

for p in Point(3,4),Point(14,5/7.):
    print (p)
#輸出
Point:x =  3.000  y =  4.000  hypot =  5.000
Point:x = 14.000  y =  0.714  hypot = 14.018

子類在增加、存儲(chǔ)名稱時(shí),并不是非常有用,相反,可以容易地通過_fields屬性來創(chuàng)建一個(gè)新的namedtuple;

>>> Point3D = namedtuple("Point3D",Point._fields + ('z',))
>>> Point3D._fields
('x', 'y', 'z')

OrderedDict

OrderedDict類似于正常的詞典,只是它記住了元素插入的順序,當(dāng)在有序的詞典上迭代時(shí),返回的元素就是它們第一次添加的順序。

class collections.OrderedDict,返回已給dict的子類,支持常規(guī)的dict的方法,OrderedDict是一個(gè)記住元素首次插入順序的詞典,如果一個(gè)元素重寫已經(jīng)存在的元素,那么原始的插入位置保持不變,如果刪除一個(gè)元素再重新插入,那么它就在末尾。

OrderedDict.popitem(last=True),popitem方法返回和刪除一個(gè)(key,value)對(duì),如果last=True,就以LIFO方式執(zhí)行,否則以FIFO方式執(zhí)行。

OrderedDict也支持反向迭代,例如reversed()

OrderedDict對(duì)象之間的相等測(cè)試,例如,list(od1.items()) == list(od2.items()),是對(duì)順序敏感的;OrderedDict和其他的映射對(duì)象(例如常規(guī)的詞典)之間的相等測(cè)試是順序不敏感的,這就允許OrderedDict對(duì)象可以在使用常規(guī)詞典的地方替換掉常規(guī)詞典。

OrderedDict構(gòu)造器和update()方法可以接受關(guān)鍵字變量,但是它們丟失了順序,因?yàn)镻ython的函數(shù)調(diào)用機(jī)制是將一個(gè)無序的詞典傳入關(guān)鍵字變量。

一個(gè)有序的詞典記住它的成員插入的順序,可以使用排序函數(shù),將其變?yōu)榕判虻脑~典,

>>> d = {"banana":3,"apple":2,"pear":1,"orange":4}
>>> # dict sorted by key
>>> OrderedDict(sorted(d.items(),key = lambda t:t[0]))
OrderedDict([('apple', 2), ('banana', 3), ('orange', 4), ('pear', 1)])
>>> # dict sorted by value
>>> OrderedDict(sorted(d.items(),key = lambda t:t[1]))
OrderedDict([('pear', 1), ('apple', 2), ('banana', 3), ('orange', 4)])
>>> # dict sorted by length of key string
>>>a =  OrderedDict(sorted(d.items(),key = lambda t:len(t[0])))
>>>a
OrderedDict([('pear', 1), ('apple', 2), ('orange', 4), ('banana', 3)])
>>> del a['apple']
>>> a
OrderedDict([('pear', 1), ('orange', 4), ('banana', 3)])
>>> a["apple"] = 2
>>> a
OrderedDict([('pear', 1), ('orange', 4), ('banana', 3), ('apple', 2)])

當(dāng)元素刪除時(shí),排好序的詞典保持著排序的順序;但是當(dāng)新元素添加時(shí),就會(huì)被添加到末尾,就不能保持已排序。

創(chuàng)建一個(gè)有序的詞典,可以記住最后插入的key的順序,如果一個(gè)新的元素要重寫已經(jīng)存在的元素,那么原始的插入位置就會(huì)改變成末尾,

>>> class LastUpdatedOrderedDict(OrderedDict):
...     def __setitem__(self,key,value):
...         if key in self:
...             del self[key]
...         OrderedDict.__setitem__(self, key, value)
... 
>>> obj = LastUpdatedOrderedDict()
>>> obj["apple"] = 2
>>> obj["windows"] = 3
>>> obj
LastUpdatedOrderedDict([('apple', 2), ('windows', 3)])
>>> obj["apple"] = 1
>>> obj
LastUpdatedOrderedDict([('windows', 3), ('apple', 1)])

一個(gè)有序的詞典可以和Counter類一起使用,counter對(duì)象就可以記住元素首次出現(xiàn)的順序;

class OrderedCounter(Counter,OrderedDict):
    def __repr__(self):
        return "%s(%r)"%(self.__class__.__name__,OrderedDict(self))

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

#和OrderDict一起使用的Counter對(duì)象
obj = OrderedCounter()
wordList = ["b","a","c","a","c","a"]
for word in wordList:
    obj[word] += 1
print (obj)

# 普通的Counter對(duì)象
cnt = Counter()
wordList = ["b","a","c","a","c","a"]
for word in wordList:
    cnt[word] += 1
print (cnt)
# 輸出
OrderedCounter(OrderedDict([('b', 1), ('a', 3), ('c', 2)]))
Counter({'a': 3, 'c': 2, 'b': 1})

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容