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

目录

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

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

1.3保存最后N个元素

1.4找到最大或最小的N个元素

1.5实现优先级队列

1.6在字典上的键映射到多个值上

1.7有序的字典

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

1.11 对切片命名

1.12找出序列中最多的元素

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

1.15根据字段将记录分组

1.16筛选序列中的元素

1.7从字典中提取子集

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

1.19数据的转化与换算

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


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

p = (4,5)
x,y = p
print(x,y)  #输出结果将返回x,y相对应的值

data = ['Alice','20','165',(2000,12,2)]
name,age,tail,brithday = data
print(name,age,tail,brithday)

name,age,tail,(year,mon,day) = data
print(year,mon,day)      #分别赋值回给到每一个变量

#如果赋值变量超出要素数量,将会报错,不信可以自己试一下。。。。嘿嘿

#只要是对象是可以迭代的,都可以赋值
s = 'hello'
a,b,c,d,e = s
print(a,e)

#想要删除某些特定的值时,可以这样做
data1 = ['yoho',50,28.8,(2022,4,26)]
_,shares,price,_ = data1
print(shares,price)

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

#分解值过多,怎么样简单得到呢?*就可以解决,类似于正则中的用法
data2 = ['zhizhi',20,165,1366548558,1564346854]
name,age,tail,*phone = data2
print(phone)  #自动生成列表

#如果想在一个成绩中去除一个最大最小值,中间值取均值,怎么做呢
def drop_frist_last(grades):
    frist,*middle,last = grades
    avg = sum(middle)/len(middle)
    print(avg)
    return avg

grades = [11,22,33,44,55,66,77,88,99,12]
drop_frist_last(grades)

#当遇到分解的字符串时,贪婪的将分配完的东西全部吃掉
line = 'nabody:*:-2:-2:Unorivileged User:/var/empty:/uers/bin/false'
uname,*files,homedir,sh = line.split(':')
print(uname,homedir,sh)

1.3保存最后N个元素

#使用collections.deque 进行匹配
from collections import deque

def search(lines,pattern,history = 5):  #定义历史记录为5
    previous_lines = deque(maxlen = history)  #创建一个长度为5 的队列
    for line in lines:
        if pattern in line:   #寻找字符所在的行
            yield line,previous_lines #yield函数将生成一个迭代器,返回具体想要的值,到此结束,形成阻塞,然而for循环将会将生成循环内所有的迭代器,单独使用调用next()函数将其不断输出。
        previous_lines.append(line)

if __name__ == '__main__':
    with open('somefile.txt') as f:    #自己的一个文件,随便是啥,啥都可以
        for line,prevlines in search(f,'python',5):
            for pline in prevlines:
                print(pline,end='')
            print(line,end='')
            print('-'*20)

#deque 生成一个固定长度的队列,当有新的记录加入时队列已满将剔除老的队列
q = deque(maxlen=3)
q.append(1)
q.append(2)
q.append(3)
print(q)

#再加入一个将剔除第一个
q.append(4)
print(q)   #输出结果为deque([2, 3, 4], maxlen=3)

#如果不指定队列长度时,将会得到一个无限的队列,可以自由的在两端进行添加和弹出操作
q1 = deque()
q1.append(1)
q1.append(2)
q1.append(3)
print(q1)

#从左边加入一个元素
q1.appendleft(5)
print(q1)   #输出结果为 deque([5, 1, 2, 3])
#弹出元素
p =  q1.pop()
print(p,q1)  #输出结果为 3 deque([5, 1, 2])
#从左侧弹出
p =  q1.popleft()
print(p,q1)   #输出结果为 5 deque([1, 2])

1.4找到最大或最小的N个元素

nums = [1,22,4,6,67,86,4,34,67,68,3445,355]
print(heapq.nlargest(3,nums))  #输出结果为 [3445, 355, 86] 其中第一个参数为限制个数,后跟数列
print(heapq.nsmallest(2,nums))   #输出结果为 [1, 4]
#如果寻找的一个最大最小值 采用max min 会更加舒服
print(max(nums))
print(min(nums))

1.5实现优先级队列

import heapq
class PriorityQueue:  #使用heapq创建一个简单的优先级队列

    def __init__(self):
        self._queue = []
        self._index = 0

    def push(self,item,priority):
        heapq.heappush(self._queue,(-priority,self._index,item))  #定义一个函数,实现元素的插入,队列将以元组形式呈现,将priority取负值是为了保证是按照元素的优先级来排列(先进先出原则,(报正第一个元素优先级最低) nidex->优先级\
                                                                    #index>先进先出
        self._index += 1

    def pop(self):   #这个实现元素的移除  弹出
        return heapq.heappop(self._queue)[-1] #返回
#使用以上类
class Item:
    def __init__(self,name):
        self.name = name
    def __repr__(self):
        return 'Item({!r})'.format(self.name)

q = PriorityQueue()
q.push(Item('foo'),1)
q.push(Item('bar'),2)
q.push(Item('spa'),9)
q.push(Item('gro'),5)
print(q.pop())  #返回Item('spa')
print(q.pop())   #返回Item('gro')
print(q.pop())   #返回Item('bar')

1.6在字典上的键映射到多个值上

a = {
    'alice':[1,2,3],'skr':[3,4,5]
}
#又或者
paris = ['a', 4], ['b', 2],['a',1]
d = {}
for key,value in paris:
    if key not in d:
        d[key] = []
    d[key].append(value)
    print(d)
# #返回结果为
# {'a': [4]}  第一个
# {'a': [4], 'b': [2]}  第二个
# {'a': [4, 1], 'b': [2]}  第三个

#使用collections 中的 defaultdict 类进行调用会变得简单
from collections import defaultdict
paris = ['a', 4], ['b', 2],['a',1]
d = defaultdict(list)
for key,value in paris:
    d[key].append(value)
print(d)

1.7有序的字典

#使用collections模块中的 OderedDict 类,当进行迭代时,可以保证按照元素 的添加顺序来,内存会扩大两倍多,因为创建额外的链表所导致的
from collections import OrderedDict
import json

d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spa'] = 3
d['gro'] = 4
print(d)  #OrderedDict([('foo', 1), ('bar', 2), ('spa', 3), ('gro', 4)])

for key in d:
    print(key,d[key])     # foo 1 bar 2 spa 3 gro 4

#将以上通过json变成字典

print(json.dumps(d))  #{"foo": 1, "bar": 2, "spa": 3, "gro": 4}

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

#如果是可哈希的值(整数,浮点数,字符串,元组)
def deque(items):
    s = set()
    for item in items:
        if item not in s:
            yield item
            s.add(item)

a = [1,3,4,5,73,3,5,53,2,4]
b = list(deque(a))
print(b)

#如果对象不是可哈希的值(list),可以略微改一哈哈
def deque(items,key=None):
    s = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in s:
            yield item
            s.add(val)

a = [{'x':1, 'y':2},{'x':2,'y':3},{'x':3,'y':4},{'x':2,'y':3},{'x':2,'y':9}]
b = list(deque(a,key = lambda d:(d['x'],d['y'])))
print(b)
c = list(deque(a,key=lambda d:d['x']))
print(c)

1.11 对切片命名

# slice()函数能够创建一个函数,这个函数能够在想要切片的位置进行切片、替换
items = [0,1,2,3,4,5,6]
a = slice(2,4)
b = items[a]
print(b)   #[2, 3]
print(items[2:4])#[2, 3]

items[a] = [4,20]
print(items)  #[0, 1, 4, 20, 4, 5, 6]

1.12找出序列中最多的元素

# 使用collections 中的Counter类进行解决,其中的most_commen()能直接告诉我们答案
words = ['hi','hello','word','world','python',
         "json",'word','jeo','json','java','list','hi','hello',
         'world','jeo','python','word','python','list','word'
         'java','word','time','text','python']

from collections import Counter
word_times = Counter(words)
top_3 = word_times.most_common(3)   #将找出最多的3个单词
print(top_3)  #[('word', 4), ('python', 4), ('hi', 2)]
#Counter相当于计数器,手动计数结果如下
print(word_times['world'])  #2
morewords = [
    'hi','word','you','and','me','python','world','so'
]
for word in morewords:
    word_times[word] += 1
print(word_times['world'])  #3
#另一种是updata()
words = ['hi','hello','word','world','python',
         "json",'word','jeo','json','java','list','hi','hello',
         'world','jeo','python','word','python','list','word'
         'java','word','time','text','python']
morewords = [
    'hi','word','you','and','me','python','world','so'
]
from collections import Counter
word_times = Counter(words)
word_times.update(morewords)
print(word_times['word']) #5

#Counter 计数器竟然可以进行运算!!
words = ['hi','hello','word','world','python',
         "json",'word','jeo','json','java','list','hi','hello',
         'world','jeo','python','word','python','list','word'
         'java','word','time','text','python']
morewords = [
    'hi','word','you','and','me','python','world','so'
]
from collections import Counter
a = Counter(words)
b = Counter(morewords)
print('a:',a,'\n',"b:",b)
print(a+b)   #Counter({'word': 5, 'python': 5, 'hi': 3, 'world': 3, 'hello': 2, 'json': 2, 'jeo': 2, 'list': 2, 'java': 1, 'wordjava': 1, 'time': 1, 'text': 1, 'you': 1, 'and': 1, 'me': 1, 'so': 1})
print(a-b)   #Counter({'word': 3, 'python': 3, 'hello': 2, 'json': 2, 'jeo': 2, 'list': 2, 'hi': 1, 'world': 1, 'java': 1, 'wordjava': 1, 'time': 1, 'text': 1})
1.13通过公共键对字典列表进行排序
# 使用operator 中的itemgetter来排序
lst = [
{'id': '1002', 'name': '小五', 'english': 12, 'Python': 23, 'java': 34},
{'id': '1003', 'name': '王五', 'english': 23, 'Python': 100, 'java': 100},
{'id': '1001', 'name': '十八', 'english': 100, 'Python': 100, 'java': 100},
{'id': 'll', 'name': '666', 'english': 222, 'python': 222, 'java': 222}
]
from operator import itemgetter

lst_by_id = sorted(lst,key = itemgetter('id'))
print(lst_by_id)
lst_by_engl = sorted(lst,key=itemgetter('english'))
print(lst_by_engl)
#同时可以进行多个键的计算
lst_by_id_java = sorted(lst,key=itemgetter('id','java'))
print(lst_by_id_java)
# 该函数同样适用于min,max()
print(max(lst,key=itemgetter('english')))
print(min(lst,key=itemgetter('java')))   #以上输出结果太长了。。。。有兴趣自己试试。没兴趣知道知道没坏处

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

#首先已定义一个类,能够对象实例以属性返回
class User:
    def __init__(self,user_id):
        self.user_id = user_id
    def __repr__(self):
        return 'User({})'.format(self.user_id)

users = [User(1),User(3),User(2)]
print(users)  #[User(1), User(3), User(2)]
print(sorted(users,key=lambda u:u.user_id))  #[User(1), User(2), User(3)]
#使用attrgetter 一样可以
from operator import attrgetter
print(sorted(users,key=attrgetter('user_id'))) #[User(1), User(2), User(3)]

1.15根据字段将记录分组

#按照指定的键进行分组,并依次进行迭代
lst = [
{'id': '1002', 'name': '小五', 'english': 12, 'Python': 23, 'java': 34,'data':'02/01/2022'},
{'id': '1003', 'name': '王五', 'english': 23, 'Python': 100, 'java': 100,
 'data':'03/01/2022'},
{'id': '1001', 'name': '十八', 'english': 100, 'Python': 100, 'java': 100,'data':'02/07/2022'},
{'id': 'll', 'name': '666', 'english': 222, 'python': 222, 'java': 222,'data':'02/01/2022'}
]
from operator import itemgetter
from itertools import groupby

lst.sort(key=itemgetter('data'))  #首先对其进行排序,因为groupby返回的迭代只对连续数据有用

for data,items in groupby(lst,key=itemgetter('data')):   #然后在分组中进行迭代
    print(data)
    for i in items:
        print('  ',i)
#如果只是存储大型数据,不用复杂,defaultdict.就可以实现
lst = [
{'id': '1002', 'name': '小五', 'english': 12, 'Python': 23, 'java': 34,'data':'02/01/2022'},
{'id': '1003', 'name': '王五', 'english': 23, 'Python': 100, 'java': 100,
 'data':'03/01/2022'},
{'id': '1001', 'name': '十八', 'english': 100, 'Python': 100, 'java': 100,'data':'02/07/2022'},
{'id': 'll', 'name': '666', 'english': 222, 'python': 222, 'java': 222,'data':'02/01/2022'}
]
from collections import defaultdict
lst_dat = defaultdict(list)
for i in lst:
    lst_dat[i['data']].append(i)

for i in lst_dat['02/01/2022']:
    print(i)
#{'id': '1002', 'name': '小五', 'english': 12, 'Python': 23, 'java': 34, 'data': '02/01/2022'}
# {'id': 'll', 'name': '666', 'english': 222, 'python': 222, 'java': 222, 'data': '02/01/2022'}

1.16筛选序列中的元素

#使用列表推导式 使用生成器通过迭代产生想要的结果
lst = [1,2,4,5,7,4,3,-1,3,-5,-3]
pos = (n for n in lst if n>0)
print(pos)   #产生一个生成器,如果想要直接以列表方式展示结果,使用list(pos)即可转换
for i in pos:
    print(i)  #依次输出结果
#对于复杂一点条件的,使用filter()处理
lst = ['1','2',4,5,'N/A','-',' ']

def is_int(val):
    try:
        x = int(val)
        return True
    except ValueError:
        return False

int_vals = list(filter(is_int,lst))   #filter返回一个迭代器
print(int_vals)

#对于数据还可以做一些计算
lst = [1,2,4,5,7,4,3,-1,3,-5,-3]
import math
sq_lst = list(math.sqrt(n) for n in lst if n>0)
print(sq_lst)  #[1.0, 1.4142135623730951, 2.0, 2.23606797749979, 2.6457513110645907, 2.0, 1.7320508075688772, 1.7320508075688772]

lst1 = list(n if n>0 else 0 for n in lst)
print(lst1)  #[1, 2, 4, 5, 7, 4, 3, 0, 3, 0, 0]

1.7从字典中提取子集

#使用列表推导式 可以解决绝大多数问题
score = {
'张三': 78, '王五': 89, '李四': 82, '赵六': 93, '大气': 34,
}

p1 = {key:value for key,value in score.items() if value>80}
print(p1)  #{'王五': 89, '李四': 82, '赵六': 93}
names = {'张三','李四','王五'}
print({key:value for key,value in score.items() if key in names})  #{'张三': 78, '王五': 89, '李四': 82}

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

from collections import namedtuple
Sub = namedtuple('Sub',['addr','num'])
sub = Sub('798521741@qq.com','18835279431')
print(sub)  #Sub(addr='798521741@qq.com', num='18835279431')
print(sub.addr)  #798521741@qq.com
#需要替换时应该采用_replace()
ssub = sub._replace(num='18235279431')
print(ssub)  #Sub(addr='798521741@qq.com', num='18235279431')

1.19数据的转化与换算

nums = [1,2,34,5,6,6]
s = sum(x * x for x in nums)  #数据的筛选和运算在同一步中进行
print(s)

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

a = {'x':1,'y':2}
b = {'x':3,"z":4}
from collections import ChainMap
c = ChainMap(a,b)
print(c['x'])  #如果有重复项只会保留第一个映射中的值
print(c['y'])  #2
print(c['z'])   #4
#采用这种方法是为了保证原始数据的更改能够显示在融合在一起的新的字典中
a['x'] = 34
print(c['x'])  #34

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值