【Python CookBook】第一章 数据结构和算法

  1. 解压不确定个数或任意个数元素的可迭代对象时可用*星号表达式,得到的是一个列表(即使为空),*_ 可接受多个需要丢弃的元素。

    first, *middle, last = grades
    first, *_ = grades
    
  2. 队列使用:collections.deque

    • 使用deque(maxlen=N) 构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候,最老的元素会自动被移除掉。
    • 在队列两端插入或删除元素时间复杂度都是O(1)
  3. 堆使用:heapq

    • heapq 模块有两个函数:nlargest() 和nsmallest() 可以从一个集合中获得最大或者最小的N 个元素列表

      # 两个函数都能接受一个关键字参数,用于更复杂的数据结构中:
      cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
      
    • 如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用min() 和max() 函数会更快。

    • 如果N的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点(sorted(items)[:N] 或者是sorted(items)[-N:])

  4. 默认初始化键字典使用:collections 模块中的defaultdict

    • 优点:defaultdict 会自动为将要访问的键(就算目前字典中并不存在这样的键)创建映射实体,即不需要单独判断键是否存在,直接使用即可。

      from collections import defaultdict
      
      d = defaultdict(list)
      d['a'].append(1)
      
      d = defaultdict(set)
      d['a'].add(1)
      
      # 普通字典要实现该功能使用setdefault()。
      d = {} # A regular dictionary
      d.setdefault('a', []).append(1)
      
  5. 有序字典使用:collections 模块中的OrderedDict 类

    • 内部维护着一个双向链表,也因此大小是普通字典的两倍
  6. 用zip()函数可以将字典的键值反转,然后可以使用min(),sorted()等函数进行运算。

    min_price = min(zip(prices.values(), prices.keys()))
    # min_price is (10.75, 'FB')
    
    # 排序
    prices_sorted = sorted(zip(prices.values(), prices.keys()))
    # prices_sorted is [(10.75, 'FB'), (37.2, 'HPQ'),
    # (45.23, 'ACME'), (205.55, 'IBM'),
    # (612.78, 'AAPL')]
    
  7. 字典的keys()方法和items()方法返回的是集合,因此可以直接做并、交、差运算,即可以找出相同的键,值或键值对等。values()方法不行,可能是因为value无法保证值互不相同。

    a = {
    'x' : 1,
    'y' : 2,
    'z' : 3
    }
    b = {
    'w' : 10,
    'x' : 11,
    'y' : 2
    }
    
    a.keys() & b.keys() # { 'x', 'y' }
    
    a.keys() - b.keys() # { 'z' }
    
    a.items() & b.items() # { ('y', 2) }
    
  8. 删除一个序列中的重复元素,如果可以无序则直接使用set()去重,如果要求有序或者元素不是hashable 类型,比如字典等时,可用下面这种方法,说明:如果key为None则直接使用item运算,如果key接受到一个匿名函数,则按匿名函数的规则,取出相应的值来运算,判断是否重复,并返回值。

    def dedupe(items, key=None):
    	seen = set()
    	for item in items:
    		val = item if key is None else key(item)
    		if val not in seen:
    			yield item
    			seen.add(val)
    			
    >>> a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
    >>> list(dedupe(a, key=lambda d: (d['x'],d['y'])))
    [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
    
  9. 利用切片对象:slice()

    SHARES = slice(20, 23)
    
    • 切片对象有三个属性a.start、a.stop、a.step

    • 可利用indices(size)控制切片大小,避免越界

      >>> s = 'HelloWorld'
      >>> a.indices(len(s))
      (5, 10, 2)
      
  10. 计数:collections.Counter,在底层实现上,一个Counter 对象就是一个字典,将元素映射到它出现的次数上,most_common()返回计数最大的前n。

    from collections import Counter
    word_counts = Counter(words)
    # 出现频率最高的3 个单词
    top_three = word_counts.most_common(3)
    print(top_three)
    # Outputs [('eyes', 8), ('the', 5), ('look', 4)]
    
    • Counter对象可以跟数学运算操作相结合

      >>> c = a + b
      >>> c
      Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'not': 2,
      'around': 2, "you're": 1, "don't": 1, 'in': 1, 'why': 1,
      'looking': 1, 'are': 1, 'under': 1, 'you': 1})
      >>> d = a - b
      
  11. 对内容是字典的列表排序:operator 模块的itemgetter,或者使用匿名函数lambda,但是itemgetter会快一点。

    from operator import itemgetter
    rows_by_fname = sorted(rows, key=itemgetter('fname'))
    rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
    
  12. 对内容不支持原生比较对象的列表排序:operator模块的attrgetter(),或者使用匿名函数lambda。min(),max()同理。

    >>> from operator import attrgetter
    >>> sorted(users, key=attrgetter('user_id'))
    [User(3), User(23), User(99)]
    
  13. 分组迭代:itertools.groupby()。使用前需要先根据指定字段的数据排序,因为groupby()进检查连续的元素。

    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)
    
    # 输出:
    07/01/2012
    {'date': '07/01/2012', 'address': '5412 N CLARK'}
    {'date': '07/01/2012', 'address': '4801 N BROADWAY'}
    07/02/2012
    {'date': '07/02/2012', 'address': '5800 E 58TH'}
    {'date': '07/02/2012', 'address': '5645 N RAVENSWOOD'}
    {'date': '07/02/2012', 'address': '1060 W ADDISON'}
    07/03/2012
    {'date': '07/03/2012', 'address': '2122 N CLARK'}
    07/04/2012
    {'date': '07/04/2012', 'address': '5148 N CLARK'}
    {'date': '07/04/2012', 'address': '1039 W GRANVILLE'}
    
  14. 过滤序列元素:尽量使用列表推导式或生成器表达式,这两种推导式都可以在推导时做处理,也可以添加过滤条件;如果略复杂则使用filter()函数,注意filter()函数返回的是迭代器;也可以使用itertools.compress()函数,第一个参数是可迭代对象,第二个参数是对应的布尔选择器序列,将可迭代对象中,选择器为True的元素。

    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]
    >>> more5
    [False, False, True, False, False, True, True, False]
    >>> list(compress(addresses, more5))
    ['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']
    
  15. 构造字典的子集:

    1. 字典推导(更快):

      p1 = {key: value for key, value in prices.items() if value > 200}
      
    2. 将元组序列传递给dict()函数:

      p1 = dict((key, value) for key, value in prices.items() if value > 200)
      
  16. 命名的元组:collections.namedtuple(),支持所有的普通元组的操作,比如索引和解压。

    >>> from collections import namedtuple
    >>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
    >>> sub = Subscriber('jonesy@example.com', '2012-10-19')
    >>> sub
    Subscriber(addr='jonesy@example.com', joined='2012-10-19')
    >>> sub.addr
    'jonesy@example.com'
    >>> sub.joined
    '2012-10-19'
    >>>
    
    • 命名元组另一个用途就是作为字典的替代,因为字典需要更多的内存空间,但是缺点是命名元组不可更改,只能使用_replace()方法,创建一个全新的命名元组并替代之前的。
  17. 转换同时计算数据:生成器表达式。

    s = sum((x * x for x in nums)) # 显示的传递一个生成器表达式对象
    s = sum(x * x for x in nums) # 更加优雅的实现方式,省略了括号
    # min(),max()同理
    
  18. 合并字典:collections 模块中的ChainMap 类。

    from collections import ChainMap
    c = ChainMap(a,b)
    print(c['x']) # Outputs 1 (from a)
    
    • 对于update()来说,他会创建一个新的字典,并且a变化并不会再影响c。而上面的方法是a变化c也会变化,因为他们仅仅是逻辑上合并了为一个,其实还是各是各。

      >>> a = {'x': 1, 'z': 3 }
      >>> b = {'y': 2, 'z': 4 }
      >>> merged = dict(b)
      >>> merged.update(a)
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值