第一章 數據結構和算法算法
1.1 將序列分解爲單獨的變量json
適用於元組、列表、字符串等。只要是可迭代的對象,均可以執行分解操做。惟一的要求是變量的總數和結構要與序列相同。數據結構
1.2 從任意長度的可迭代對象中分解元素app
「*表達式」數據結構和算法
如下代碼中使用的「*args」,若是去掉*,是會報錯的。函數
records = [('foo',1,2),('bar','hello'),('foo',3,4)] for tag,*args in records: print(tag,*args)
拆分操做,和split結合使用,會實現很是好用的功能:性能
line = 'nobody:*:-2:-2:Unprivileged User:/Var/empty:/usr/bin/false' uname,*fields,homedir,sh = line.split(':')
1.3 保留最後N個元素ui
下邊一段代碼還不是特別理解,對生成器比較生疏。編碼
from collections import deque def search(lines,pattern,history): previous_lines = deque(maxlen=history) for line in lines: if pattern in line: yield line,previous_lines previous_lines.append(line) if __name__ == '__main__': with open('somefile.txt') as f: for line,prevlines in search(f,'Python',5): for pline in prevlines: print(pline,end='') print(line,end='') print('-'*20)
deque(maxlen=N)建立一個固定長度的隊列,有新元素添加時,會自動刪除最老的記錄。spa
不指定長度的時候,建立一個無界限的隊列:
from collections import deque q = deque() q.append(1) q.append(2) q.append(3) print(q) q.append(4)#右邊添加元素 q.appendleft(0)#左邊添加元素 print(q) q.pop()#刪除最右邊元素 print(q) q.popleft()#刪除左邊元素 print(q)
1.4 找到最大或最小的N個元素
heapq模塊中的nlargest和nsmallest函數:
import heapq nums = [1,8,2,23,7,-4,16,23,42,37,2] print(heapq.nlargest(3,nums)) print(heapq.nsmallest(3,nums))
提供一個參數key,使其工做在更復雜的結構上:
portfolio = [{'name':'IBM','shares':100,'price':91.1}, {'name':'AAPL','shares':50,'price':543.22}, {'name':'FB','shares':200,'price':21.09}, {'name':'HPQ','shares':35,'price':31.75}, {'name':'YHOO','shares':45,'price':16.35}, {'name':'ACME','shares':75,'price':115.65}] cheap = heapq.nsmallest(3,portfolio,key=lambda s: s['price']) print(cheap) expensive = heapq.nlargest(3,portfolio,key=lambda s: s['price']) print(expensive)
若是正在尋找最大或者最小的N個元素,且同集合中元素的總數目相比,N很小,那麼可使用如下函數(性能更好):爲何?
nums = [1,8,2,23,7,-4,16,23,42,37,2] heap = list(nums) #找到第3小的元素 heapq.heappop(heap) heapq.heappop(heap) heapq.heappop(heap)
當所要尋找的元素數量相對較小時,nlargest和nsmallest函數纔是最適用的。若是隻是簡單尋找最大和最小值,那麼max和min函數會更快。若是N和集合自己大小差很少,一般更快的方法是先對集合排序,而後進行切片操做( sorted(items)[:N] 和sorted(items)[-N:] )。
1.5 實現優先級隊列(暫時擱置)
1.6 在字典中將鍵映射到多個值上
一鍵多值字典,可使用collections模塊中的defaultdict類:
from collections import defaultdict d = defaultdict(list) d['a'].append(1) d['a'].append(2) d['b'].append(3) print(d) d = defaultdict(set) d['a'].add(1) d['a'].add(2) d['b'].add(3) print(d)
使用列表仍是集合,取決於實際須要,注重順序,則使用列表;但願去除重複值,則使用集合。
以上方法會自動建立字典表項(什麼東西)以待稍後訪問,也能夠在普通字典上使用setdefault方法:
d = {} d.setdefault('a',[]).append(1) d.setdefault('a',[]).append(2) d.setdefault('b',[]).append(3) print(d)
1.7 讓字典保持有序
collections模塊中的OrderedDict類可以使字典在迭代的時候保持嚴格按照元素初始添加的時候的順序:
from collections import OrderedDict d = OrderedDict() d['foo'] = 1 d['bar'] = 2 d['spam'] = 3 d['grok'] = 4 for key in d: print(key,d[key])
由於對字典的特性瞭解的還不夠深,因此對這種好處的理解不是很深入。
json編碼時嚴格控制字段的順序,就可使用此種方法:
import json json.dumps(d)
OrderedDict內部維護了一個雙向鏈表,根據元素添加的順序來排列鍵的位置,大小是普通字典的兩倍多,在使用的時候就要衡量其帶來的好處和增長的額外內存開銷的缺點。
1.8 與字典有關的計算問題
zip()會將字典的鍵和值反轉過來,而後進行一些計算,好比求最值、排序等:
prices = {'ACME':45.23, 'AAPL':612.78, 'IBM':205.55, 'HPQ':27.20, 'FB':10.75} min_prices = min(zip(prices.values(),prices.keys())) max_prices = max(zip(prices.values(),prices.keys())) sorted_prices = sorted(zip(prices.values(),prices.keys()))
zip建立一個迭代器(?),內容只能被消費一次,如下代碼會報錯:
prices_and_names = zip(prices.values(),prices.keys()) print(min(prices_and_names)) print(max(prices_and_names))
在字典上執行常規的數據操做(例如min(prices)),結果是隻處理鍵,而不處理值;若是想利用字典的values()方法解決這個問題,結果只看到值得結果看不到對應的鍵的信息。
zip將字典的鍵值對反轉爲值鍵對,在這樣的元組上進行比較時,值會先進行比較,而後再比較鍵。若是有多個鍵對應着相同的值,這時候key就將稱爲斷定結果的依據。
1.9 在兩個字典中尋找相同點
經過keys()或者items()執行集合操做便可實現:
a = {'x':1,'y':2,'z':3} b = {'w':10,'x':11,'y':2} a.keys() & b.keys() a.keys() - b.keys() a.items() & b.items() c = {key:a[key] for key in a.keys() - {'z','w'}}
注意,對於集合的values()方法不支持集合操做。能夠將值轉化爲集合後來操做。
1.10 從序列中移除重複項且保持元素間順序不變
1.11 對切片命名
從字符串的固定位置取出具體的數據:
record = '....................100.......513.25..........' cost = int(record[20:23]) * float(record[30:36])
避免使用許多神祕難懂的硬編碼索引,使用切片命名:
shares = slice(20,23) prices = slice(30,36) cost = int(record[shares]) * float(record[prices])
slice對象實例s能夠經過s.start, s.stop, s.step屬性獲取實例對象的信息:
a = slice(2,40,5)
a.start
a.stop
a.step
能夠經過使用indices(size)方法將切片映射到特定大小的序列上,會返回一個(start, stop, step)元組。
s = 'HelloWorld' a.indices(len(s)) for i in range(*a.indices(len(s))): print(s[i])
range參數裏的*號是作什麼的呢?
1.12 找出序列中出現次數最多的元素
collections模塊中的Counter類:
words = ["twinkle", "twinkle", "little", "star", "how", "i", "wonder", "what", "you", "are", "up", "above", "the", "world", "so", "high", "like", "a", "diamond", "in", "the", "sky", "twinkle", "twinkle", "little", "star", "how", "i", "wonder", "what", "you", "are"] from collections import Counter wordsCounts = Counter(words) top_three = wordsCounts.most_common(3)
在底層實現中,Counter是一個字典,在元素和出現次數之間作了映射,咱們能夠經過如下方式查看某個單詞出現的次數:
print(wordsCounts["i"])
使用update方法增長計數:
morewords = ["like", "a", "diamond", "in", "the", "sky"] wordsCounts.update(morewords) print(wordsCounts)
Counter對象能夠同各類數學運算操做結合起來:
a = Counter(words) b = Counter(morewords) c = a+b print(c) d = a-b print(d)
1.13 經過公共鍵對字典列表排序
根據一個或者多個字典中的值對列表排序,利用operator模塊中的itemgetter函數:
rows = [{"fname":"Brain" , "lname": "Jones", "uid": 1003}, {"fname":"David" , "lname": "Beazley", "uid": 1002}, {"fname":"John" , "lname": "Cleese", "uid": 1001}, {"fname":"Big" , "lname": "Jones", "uid": 1004}] from operator import itemgetter rows_by_fname = sorted(rows, key=itemgetter('fname')) print(rows_by_fname) rows_by_uid = sorted(rows, key=itemgetter('uid')) print(rows_by_uid)
itemgetter函數能夠接受多個參數:
rows_by_lfname = sorted(rows, key=itemgetter('lname', 'fname')) print(rows_by_lfname)
有時候用lambda表達式取代itemgetter()的功能:
rows_by_fname = sorted(rows, key=lambda r: r['fname']) print(rows_by_fname)
除了可使用sorted()函數以外,還能夠用與min()與max()函數。
1.14 對不原生支持比較操做的對象排序