python cookbook 1数据结构和算法(4)

16过滤序列元素

itertools.compress()

最简单的方式是用list表达式过滤
>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> [n for n in mylist if n > 0]
[1, 4, 10, 2, 3]
但是如果输入量很大,最好用生成器
>>> pos = (n for n in mylist if n > 0)
>>> pos
<generator object <genexpr> at 0x7efdb34b6d20>
>>> for i in pos:
...     print i
... 
1
4
10
2
3
如果过滤准则比较复杂,最好用内建的filter方法
>>> values = ['1', '2', '-3', '-', '4', 'N/A', '5']
>>> def is_int(val):
...     try:
...        x=int(val)
...        return True
...     except ValueError:
...        return False
... 
>>> filter(is_int,values)
['1', '2', '-3', '4', '5']
另一个比较实用的过滤器是itertools.compress(),需要一个迭代元素和一个对应的boolean序列作为输入
>>> from itertools import compress
>>> counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
>>> more5 = [n > 5 for n in counts]
>>> more5
[False, False, True, False, False, True, True, False]
>>> compress(counts,more5)
<itertools.compress object at 0x7efdb347c190>
compress返回的是一个迭代序列,需要用list()进行类型转换
>>> list(compress(counts,more5))
[10, 7, 6]

17生成dict的子序列

prices = {
'ACME': 45.23,
'AAPL': 612.78,
'IBM': 205.55,
'HPQ': 37.20,
'FB': 10.75
}>>> p1 = { key:value for key, value in prices.items() if value > 200 }
>>> p1
{'AAPL': 612.78, 'IBM': 205.55}

18将name映射到序列元素
collections.namedtuple()是一个工厂方法,返回一个标准的tuple类型的子集,你需要提供类型名称和应该有的域.

>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriberxx', ['addr', 'joined'])
程序中,'Subscriberxx'是类型名称, ['addr', 'joined']是域 
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriberxx(addr='jonesy@example.com', joined='2012-10-19')
namedtuple()虽然像一个类实例,实际上确实和tuple交互支持常用的tuple操作,如索引和解包
>>> len(sub)
2
>>> addr, joined = sub
>>> addr
'jonesy@example.com'
>>> joined
'2012-10-19'

namedtuple()的一个重要用处是取代dict,dict需要更多的存储空间,当需要建包含大量dict的数据时用namedtuple()更高效,但有一点需要注意,namedtuple()是不可变的,(tuple是不可变的) .

如果需要改变,则使用_replace(),这会产生一个新的
>>> Stock = namedtuple('Stock', ['name', 'shares', 'price'])
>>> s = Stock('ACME', 100, 123.45)
>>> s.share=75
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Stock' object has no attribute 'share'
>>> s=s._replace(shares=75)
>>> s
Stock(name='ACME', shares=75, price=123.45)
我们可以利用_replace()创建一个包含默认值的原型
>>> Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])
>>> stock_prototype = Stock('', 0, 0.0, None, None)
>>> def dict_to_stock(s):
...     return stock_prototype._replace(**s)
... 
>>> a = {'name': 'ACME', 'shares': 100, 'price': 123.45}
>>> dict_to_stock(a)
Stock(name='ACME', shares=100, price=123.45, date=None, time=None)
>>> b = {'name': 'ACME', 'shares': 100, 'price': 123.45, 'date': '12/17/2012'}
>>> dict_to_stock(b)
Stock(name='ACME', shares=100, price=123.45, date='12/17/2012', time=None)
>>>

19同时转换和归并数据

>>> nums = [1, 2, 3, 4, 5]
>>> s = sum((x * x for x in nums)) # 显示的传递一个生成器表达式对象
>>> s = sum(x * x for x in nums)# 更加优雅的实现方式,省略了括号
>>> s
55
使用生成器是更优雅和高效的方式,应为省去了创建一个临时的tuple或list的损耗

20将多个映射合并为一个
collections.ChainMap(仅python3适用)

>>> from collections import ChainMap
>>> a = {'x': 1, 'z': 3 }
>>> b = {'y': 2, 'z': 4 }
>>> c = ChainMap(a,b)
>>> c
ChainMap({'x': 1, 'z': 3}, {'z': 4, 'y': 2})
>>> c['x']
1
>>> c['y']
2
>>> c['z']
3
ChainMap只是把多个映射逻辑上组合在一起,如果有多个相同的key,则取第一个
>>> len(c)
3
>>> list(c.keys())
['x', 'z', 'y']
>>> list(c.values())
[1, 3, 2]
对ChainMap的操作只会对第一个映射产生影响
>>> c['z']=10
>>> c['w']=3
>>> del c['x']
>>> c
ChainMap({'w': 3, 'z': 10}, {'z': 4, 'y': 2})
>>> a
{'w': 3, 'z': 10}
>>> del c['y']
---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)
<ipython-input-5-df3e26fa6544> in <module>()
----> 1 del c['y']

/usr/lib/python3.4/collections/__init__.py in __delitem__(self, key)
    866             del self.maps[0][key]
    867         except KeyError:
--> 868             raise KeyError('Key not found in the first mapping: {!r}'.format(key))
    869 
    870     def popitem(self):

KeyError: "Key not found in the first mapping: 'y'"
---------------------------------------------------------------------------

ChainMap还可以用new_child(),parents添加和删除映射
>>> values=ChainMap()
>>> values['x']=1
>>> values=values.new_child()
>>> values['x']=2
>>> values=values.new_child()
>>> values['x']=3
>>> values
ChainMap({'x': 3}, {'x': 2}, {'x': 1})
>>> values['x']
3
>>> values=values.parents
>>> values
ChainMap({'x': 2}, {'x': 1})
>>> values['x']
2
有一种取代ChainMap的方式是用update()
>>> a = {'x': 1, 'z': 3 }
>>> b = {'y': 2, 'z': 4 }
>>>b.update(a)
>>> b
{'x': 1, 'z': 3, 'y': 2}
>>> a
{'x': 1, 'z': 3}
>>> a['x']=13
>>> a
{'x': 13, 'z': 3}
>>> b
{'x': 1, 'z': 3, 'y': 2}
******************
这两种方式有一个重要的区别,update原dict的改变不会影响到合并后的dict,但ChainMap会
******************
>>> a = {'x': 1, 'z': 3 }
>>> b = {'y': 2, 'z': 4 }
>>> merged = ChainMap(a, b)
>>> merged['x']
1
>>> a['x']=32
>>> merged['x']
32

转载于:https://my.oschina.net/u/1409733/blog/399270

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值