1.数据结构的集合操作模块 —— collections
2.解压可迭代对象赋值给多个变量 —— 使用星号表达式
# 剔除最高最低分,统计平均分
def drop_first_last(grades):
first,*middle,last = grades # middle是一个列表类型变量
return avg(middle)
3.字符串分割 —— line.split(’:’)
保留有限历史记录 —— collections.deque
# 在多行上面做简单的文本匹配, 并返回匹配所在行的最后N行
from collections import deque
def search(lines, pattern, history=5):
previous_lines = deque(maxlen=history)
for line in lines:
if pattern in line:
yield line, previous_lines
# yield 表达式的生成器函数,将搜索过程代码和使用搜索结果代码解耦
previous_lines.append(line)
# 使用 deque(maxlen=N) 构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候, 最老的元素会自动被移除掉
q = deque(maxlen=3)
q.append(1)
q.append(2)
q.append(3)
# deque([1, 2, 3], maxlen=3)
q.append(4)
# deque([2, 3, 4], maxlen=3)
# deque 类可以被用在任何你只需要一个简单队列数据结构的场合。 如果你不设置最大队列大小,那么就会得到一个无限大小队列
q = deque()
q.append(1)
q.append(2)
q.append(3)
q.appendleft(4)
# deque([4, 1, 2, 3])
q.pop()
# deque([4, 1, 2])
q.popleft()
# 4
# 在队列两端插入或删除元素时间复杂度都是 O(1),在列表的开头插入或删除元素的时间复杂度为 O(N)
4.查找最大或最小的 N 个元素 —— heapq 模块:nlargest()、 nsmallest()
import heapq # 堆结构模块
# Example 1
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]
# Example 2
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'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
# 将list转为堆数据结构
# 堆数据结构最重要的特征是 heap[0] 永远是最小的元素。
# 并且剩余的元素可以很容易的通过调用 heapq.heappop() 方法得到, 该方法会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素(这种操作时间复杂度仅仅是 O(log N),N 是堆大小)
1) 当要查找的元素个数相对比较小:nlargest() 、 nsmallest()
2)查找唯一的最小或最大(N=1)的元素:min() 、max()
3)如果 N 的大小和集合大小接近的时候,先排序这个集合然后再使用切片操作:sorted(items[:N] 、sorted(items)[-N:] )
5.实现一个优先级队列
>>> q = PriorityQueue()
>>> q.push(Item('foo'), 1)
>>> q.push(Item('bar'), 5)
>>> q.push(Item('spam'), 4)
>>> q.push(Item('grok'), 1)
> q.pop()
# pop() 操作返回优先级最高的元素。如果两个有着相同优先级的元素,pop 操作按照它们被插入到队列的顺序返回的
# 函数 heapq.heappush() 和 heapq.heappop() 分别在队列 _queue 上插入和删除第一个元素
# 并且队列 _queue 保证第一个元素拥有最高优先级( 1.4 节已经讨论过这个问题)。
# heappop() 函数总是返回”最小的”的元素,这就是保证队列pop操作返回正确元素的关键。
# 另外,由于 push 和 pop 操作时间复杂度为 O(log N),其中 N 是堆的大小,因此就算是 N 很大的时候它们运行速度也依旧很快
6.字典中的键映射多个值
from collections import defaultdict
d = defaultdict(list)
for key, value in pairs:
d[key].append(value)
7.字典排序,在迭代或序列化这个字典的时候能够控制元素的顺序
# 控制一个字典中元素的顺序,在迭代操作的时候它会保持元素被插入时的顺序
from collections import OrderedDict
# 一个 OrderedDict 的大小是一个普通字典的两倍
8.字典运算
# 对字典值执行计算操作,通常需要使用 zip() 函数先将键和值反转过来
prices = {
'ACME': 45.23,
'AAPL': 612.78,
'IBM': 205.55,
'HPQ': 37.20,
'FB': 10.75
}
# zip() 函数创建的是一个只能访问一次的迭代器
min_price = min(zip(prices.values(), prices.keys()))
max_price = max(zip(prices.values(), prices.keys()))
# 使用 zip() 和 sorted() 函数来排列字典数据
prices_sorted = sorted(zip(prices.values(), prices.keys()))
9.查找两字典的相同点
# 为了寻找两个字典的相同点,可以简单的在两字典的 keys() 或者 items() 方法返回结果上执行集合操作
# Find keys in common
a.keys() & b.keys() # { 'x', 'y' }
# Find keys in a that are not in b
a.keys() - b.keys() # { 'z' }
# Find (key,value) pairs in common
a.items() & b.items() # { ('y', 2) }
# Make a new dictionary with certain keys removed
c = {key:a[key] for key in a.keys() - {'z', 'w'}}
10.删除序列相同元素并保持顺序
a = [1, 5, 2, 1, 9, 1, 5, 10]
sorted(set(a))
11.命名切片
# slice() 函数创建了一个切片对象
items = [0, 1, 2, 3, 4, 5, 6]
a = slice(2, 4)
a = slice(5, 50, 2)
a.start
a.stop
a.step
# 通过调用切片的 indices(size) 方法将它映射到一个已知大小的序列上:返回一个三元组 (start, stop, step)
s = 'HelloWorld'
a.indices(len(s))
# (5, 10, 2)
12.序列中出现次数最多的元素
words = [
'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
'my', 'eyes', "you're", 'under'
]
from collections import Counter
word_counts = Counter(words)
# 出现频率最高的3个单词
top_three = word_counts.most_common(3)
print(top_three)
word_counts['not'] # 1
morewords = ['why','are','you','not','looking','in','my','eyes']
word_counts.update(morewords) # 手动增加计数
Counter(words)
Counter(morewords)
13.通过某个关键字排序一个字典列表
rows = [
{'fname': 'Brian', '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'))
rows_by_uid = sorted(rows, key=itemgetter('uid'))
print(rows_by_fname)
print(rows_by_uid)
rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
print(rows_by_lfname)
# itemgetter() 也可以用 lambda 表达式代替
rows_by_fname = sorted(rows, key=lambda r: r['fname'])
rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
min(rows, key=itemgetter('uid'))
max(rows, key=itemgetter('uid'))
14.排序不支持原生比较的对象
from operator import attrgetter
# attrgetter() 函数会运行的快点,并且还能同时允许多个字段进行比较
sorted(users, key=attrgetter('user_id'))
by_name = sorted(users, key=attrgetter('last_name', 'first_name'))
15.通过某个字段将记录分组
from operator import itemgetter
from itertools import groupby
rows = [
{'address': '5412 N CLARK', 'date': '07/01/2012'},
{'address': '5148 N CLARK', 'date': '07/04/2012'},
{'address': '5800 E 58TH', 'date': '07/02/2012'},
{'address': '2122 N CLARK', 'date': '07/03/2012'},
{'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
{'address': '1060 W ADDISON', 'date': '07/02/2012'},
{'address': '4801 N BROADWAY', 'date': '07/01/2012'},
{'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
]
# Sort by the desired field first
rows.sort(key=itemgetter('date')
# Iterate in groups
for date, items in groupby(rows, key=itemgetter('date')):
print(date)
for i in items:
print(' ', i)
16.过滤序列元素 —— filter()(返回一个迭代器)
values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):
try:
x = int(val)
return True
except ValueError:
return False
ivals = list(filter(is_int, values))
print(ivals)
# Outputs ['1', '2', '-3', '4', '5']
# 过滤工具:itertools.compress() : 返回一个迭代器
addresses = [
'5412 N CLARK',
'5148 N CLARK',
'5800 E 58TH',
'2122 N CLARK',
'5645 N RAVENSWOOD',
'1060 W ADDISON',
'4801 N BROADWAY',
'1039 W GRANVILLE',
]
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
from itertools import compress
# 一个 iterable 对象和一个相对应的 Boolean 选择器序列作为输入参数,输出 iterable 对象中对应选择器为 True 的元素
more5 = [n > 5 for n in counts]
list(compress(addresses, more5))
17.从字典中提取子集
prices = {
'ACME': 45.23,
'AAPL': 612.78,
'IBM': 205.55,
'HPQ': 37.20,
'FB': 10.75
}
p1 = dict((key, value) for key, value in prices.items() if value > 200)
# Make a dictionary of tech stocks
tech_names = { 'AAPL', 'IBM', 'HPQ', 'MSFT' }
p2 = { key:prices[key] for key in prices.keys() & tech_names }
# p2运行时间大概比p1慢 1.6 倍
18.映射名称到序列元素 —— collections.namedtuple()
from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])
# Create a prototype instance
stock_prototype = Stock('', 0, 0.0, None, None)
# Function to convert a dictionary to a Stock
def dict_to_stock(s):
return stock_prototype._replace(**s)
a = {'name': 'ACME', 'shares': 100, 'price': 123.45}
dict_to_stock(a)
19.转换并同时计算数据
# 计算平方和
nums = [1, 2, 3, 4, 5]
s = sum(x * x for x in nums)
# Determine if any .py files exist in a directory
import os
files = os.listdir('dirname')
if any(name.endswith('.py') for name in files):
print('There be python!')
else:
print('Sorry, no python.')
# Output a tuple as CSV
s = ('ACME', 50, 123.45)
print(','.join(str(x) for x in s))
# Data reduction across fields of a data structure
portfolio = [
{'name':'GOOG', 'shares': 50},
{'name':'YHOO', 'shares': 75},
{'name':'AOL', 'shares': 20},
{'name':'SCOX', 'shares': 65}
]
min_shares = min(s['shares'] for s in portfolio)
20.合并多个字典或映射
a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }
# ChainMap
from collections import ChainMap
c = ChainMap(a,b)
# update()
merged = dict(b)
merged.update(a)
# dict()
d = dict(a,**b)