python cookbook:第一章 数据结构和算法

1.1 将序列分解为单独的变量

p=(4,5)
x,y=p

只要对象是可迭代的,就可以执行分解操作。

字符串、文件、迭代器、生成器都可以。

字符串:

s='hello'
a,b,c,d,e=s

想要丢弃特定的值,使用一个用不到的变量名就可以了。


1.2 从任意长度的可迭代对象中分解元素

first,*middle,last=grades

*middle代表了中间的n个元素。

可以用在递归算法,不过python不推荐使用递归。


1.3 保留最后n个元素

这里可以使用队列collections.deque。

有append(),pop(),appendleft(),popleft()几种常用方法。


1.4 找到最大或者最小的n个元素

可以使用nlargest()和nsmallest(),这两个函数可以使用key,即lambda表达式。

当待排序元素总数过大时,应该采用heapq(堆排序),获得最佳性能。

如果只想找一个最大/最小元素,可以使用min(),max()。


1.5 实现优先级队列

可以使用堆排序来实现,参考heapq。

heapq.heappush()负责向堆中加入元素

heapq.heappop()返回最小的元素

优先级队列中的元素采用(-priority,index,item)数据结构实现,优先级取负值因为heap是由小到大排序,index是为了优先级相同的元素依然可以正确排序。


1.6 字典中将键映射到多个值上

在字典item中嵌套容器,如:

d={
   'a':[1,2,3],
   'b':{4,5}
   }

为了方便的创建这样的字典,我们使用collections.defaultdict类。

d=defaultdict(list)
d['a'].append(1)

当然,也可以使用普通字典的setdefault():

d={}
d.setdefault('a',[]).append(1)


1.7 让字典保持有序

使用collections.OrderDict,有序的字典,内部维护双向链表,内存开销很大。


1.8 与字典有关的计算问题

在对字典内容排序时,需要先用zip()将键值对翻转过来,如:

min_price=min(zip(prices.values(),prices.keys()))
如果需要排序,zip配合sort。

请注意,zip所创建的是一个迭代器,它的内容只能使用一次。


1.9 在两个字典中寻找相同点

寻找相同的键:

a.keys() & b.keys() 


寻找a中有,b中没有的

a.keys()-b.keys()

寻找相同的值:

a.items & b.items()

keys()方法会返回keys-view对象,支持集合操作。

items()方法会返回items-view对象,支持集合操作。

但是values()方法不支持集合操作。


1.10 从序列中移除重复项且保持元素间顺序不变

先说明一下可哈希:

简单的说就是不可变,如数值,字符串,元组,frozenset之类的,而列表、字典、集合之类的就不行。

如果序列中的值是可哈希的,可以使用集合实现:

def dedupe(items):
    seen=set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)
            
a=[1,1,2,3,4,5,4]
list(dedupe(a))

如果存在不可哈希的对象,

def dedupe(items):
    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=[1,1,2,3,4,5,4]
list(dedupe(a))

其实,也可以直接set(a),来获得一个集合。但是这样做会打乱原有顺序。



1.11 对切片命名

record='..........11........22'
SHARES=slice(10,11)
PRICE=slice(20,21)
cost=int(record[SHARES])*int(record[PRICE])

在平面文件处理中比较常用,如文件读取。对于切片对象,有start(),stop(),step()函数可以使用。


1.12 找出序列中出现次数最多的元素

collections中的Counter类和most_common()方法可以解决。

from collections import Counter
word_counts=Counter(words)
top_three=word_counts.most_common(3)

如果需要增加计数,可以使用update()方法

Counter也可以与数学运算结合起来


1.13 通过公共键对字典列表排序

利用operator模块中的itemgetter函数对这类结构进行排序。同样可用于min、max。

from operator import itemgetter
row_by_name=sorted(rows,key=itemgetter('fname'))

1.14 对不原生支持比较操作的对象排序

可以使用operator的attrgetter模块。同样可用于min、max。

sorted(users,key=attrgetter('user_id'))


1.15 根据字段将记录分组

使用itertools.groupby()函数。

from operator import itemgetter
from itertools import groupby

rows.sort(key=itemgetter('date'))
for date,items in groupby(rows,key=itemgetter('date')):
    print date
    for i in items:
        print (' ',i)

注意:groupby只能检查连续的项,所以要先排序。


1.16 筛选序列中的元素

可以使用列表推导式,例如:

mylist=[1,2,3,4,5]
[n for n in mylist if n>3]

但是这样内存占用会过大。可以使用生成器表达式:

pos=(n for n in mylist if n>4)
for x in pos:
    print(x)

对于复杂的逻辑,可以使用filter()+筛选逻辑函数:

val=['1','2','x','-']
def is_int(val):
    try:
        x=int(val)
        return True
    except ValueError:
        return False
    
ivals=list(filter(is_int,val))
print (ivals)


1.17 从字典中提取子集

可以利用字典推导式:

prices={
        'aaa':1,
        'bbb':2
        }
p1={key:value for key,value in prices.items() if value>1}


1.18 将名称映射到序列的元素中

我们使用collections.namedtuple():

from collections import namedtuple
Subscriber= namedtuple('Subscriber',['addr','joined'])
sub=Subscriber('111@qq.com','2012-1-1')
使用方法与字典基本一致,注意它是不可变的,修改属性需要用_replace()方法来实现。

上述方法可以用于处理缺失字段的命名元组。


1.19 同时对数据做转换和换算

可以在函数参数中使用生成器表达式

num=[1,2,3,4,5]
sum(x*x for x in num)
sum([x*x for x in num])

注意,上下两个语句是不一样的,上边只使用生成器表达式,下面使用了列表表达式,多了一个步骤,创建额外的列表(只使用一次就作废)。


1.20 将多个映射合并为单个映射

使用collections.ChainMap():

a={
   'a':1,
   'b':2
   }
b={
   'c':3,
   'd':4
   }

from collections import ChainMap
c=ChainMap(a,b)


似乎2.7没有ChainMap啊,无法导入。

如果a、b有重复的值,采用第一个的。

修改操作出现在第一个映射结构上。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值