CookBook~数据结构和算法
1.11 命名切片
SHARES = slice(20, 23) PRICE = slice(31, 37) cost = int(record[SHARES]) * float(record[PRICE])
- 避免大量无法理解的硬编码下标
- 代码更加清晰可读
a = slice(5, 50, 2) a.start # 5 a.stop # 50 a.step # 2 s = 'HelloWorld' a.indices(len(s)) # (5, 10, 2)
切片的indices(size)方法将它映射到一个确定大小的序列上,这个方法返回一个三元组(start,stop,step),所有值都会被合适的缩小以满足边界限制,从而使用的时候避免出现IndexError异常
1.12 序列中出现次数最多的元素
collections.Counter
- Counter 对象可以接受任意的 hashable 序列对象
- 一个 Counter 对象就是一个字典,将元素映射到它出现的次数上
- 支持数学运算操作
- 使用update()方法更新计数
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) # [('eyes', 8), ('the', 5), ('look', 4)] print(top_three)
1.13 通过某个关键字排序一个字典列表
operator.itemgetter
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')) rows_by_lfname = sorted(rows, key=itemgetter('lname','fname')) # lambda表达式代替 rows_by_fname = sorted(rows, key=lambda r: r['fname']) rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
1.14 排序不支持原生比较的对象
operator.attrgetter
class User: def __init__(self, user_id): self.user_id = user_id def __repr__(self): return 'User({})'.format(self.user_id) def sort_notcompare(): users = [User(23), User(3), User(99)] print(users) print(sorted(users, key=lambda u: u.user_id)) from operator import attrgetter sorted(users, key=attrgetter('user_id')) # [User(3), User(23), User(99)] sorted(users, key=attrgetter('last_name', 'first_name'))
1.15 通过某个字段将记录分组
itertools.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'}, ] from operator import itemgetter from itertools import groupby # 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) from collections import defaultdict
rows_by_date = defaultdict(list) for row in rows: rows_by_date[row['date']].append(row)
groupby() 仅仅检查连续的元素,如果事先并没有排序完成的话,分组函数将得不到想要的结果。
只想根据date字段将数据分组到一个大的数据结构中去,并且允许随机访问,可使用 defaultdict() 来构建一个多值字典。
1.16 过滤序列元素
- 使用列表推导,大数据量输入会产生一个非常大的结果集,占用大量内存。
- 使用生成器表达式迭代产生过滤的元素。
- 过滤规则复杂,将过滤代码放到一个函数中,使用内建的 filter() 函数。
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
more5 = [n > 5 for n in counts] # [False, False, True, False, False, True, True, False] list(compress(addresses, more5)) # ['5800 E 58TH', '4801 N BROADWAY', '1039 W GRANVILLE']
itertools.compress() ,它以一个 iterable 对象和一个相对应的Boolean选择器序列作为输入参数。然后输出 iterable 对象中对应选择器为True的元素。
1.17 从字典中提取子集
prices = { 'ACME': 45.23, 'AAPL': 612.78, 'IBM': 205.55, 'HPQ': 37.20, 'FB': 10.75 } # 方法1: Make a dictionary of all prices over 200 p1 = {key: value for key, value in prices.items() if value > 200} # 方法1: Make a dictionary of tech stocks tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'} p2 = {key: value for key, value in prices.items() if key in tech_names} # 方法2: 方案1,字典推导方式表意更清晰 p1 = dict((key, value) for key, value in prices.items() if value > 200) # 方法3: 这种方案大概比第一种方案慢1.6倍 tech_names = { 'AAPL', 'IBM', 'HPQ', 'MSFT' } p2 = { key:prices[key] for key in prices.keys() & tech_names }
1.18 映射名称到序列元素
collections.namedtuple
from collections import namedtuple
Subscriber = namedtuple('Subscriber', ['addr', 'joined']) sub = Subscriber('jonesy@example.com', '2012-10-19') # Subscriber(addr='jonesy@example.com', joined='2012-10-19') sub.addr # 'jonesy@example.com' sub.joined # '2012-10-19'
namedtuple的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组操作,比如索引和解压。
命名元组另一个用途就是作为字典的替代,因为字典存储需要更多的内存空间。如果你需要构建一个非常大的包含字典的数据结构,那么使用命名元组会更加高效。但是需要注意的是,不像字典那样,一个命名元组是不可更改的。
使用命名元组实例的 _replace() 方法, 它会创建一个全新的命名元组并将对应的字段用新的值取代。_replace() 方法还有一个很有用的特性就是当你的命名元组拥有可选或者缺失字段时候,它是一个非常方便的填充数据的方法。
1.19 转换并同时计算数据
nums = [1, 2, 3, 4, 5] s = sum([x * x for x in nums]) # 显示的传递一个生成器表达式对象 s = sum((x * x for x in nums)) # 显示的传递一个列表推导式对象 s = sum(x * x for x in nums)
1.20 合并多个字典或映射
collections.ChainMap
a = {'x': 1, 'z': 3 } b = {'y': 2, 'z': 4 } from collections import ChainMap
c = ChainMap(a,b) print(c['x']) # Outputs 1 (from a) print(c['y']) # Outputs 2 (from b) print(c['z']) # Outputs 3 (from a) len(c) # 3 list(c.keys()) # ['x', 'y', 'z'] list(c.values()) # [1, 2, 3]
- 接受多个字典并将它们在逻辑上变为一个字典
- 如果出现重复键,那么第一次出现的映射值会被返回
- 对于字典的更新或删除操作总是影响的是列表中第一个字典
作为ChainMap的替代,可使用update()方法将两个字典合并。它需要创建一个完全不同的字典对象(或者是破坏现有字典结构)。同时,如果原字典做了更新,这种改变不会反应到新的合并字典中去。
本文地址:https://blog.csdn.net/weixin_40108079/article/details/108245763
上一篇: 某大型互联网企业-Java工程师招聘
下一篇: php要先做html吗