第一章:数据结构和算法

文章目录

第一节:关于赋值

任何的序列 (或者是可迭代对象) 可以通过一个简单的赋值语句解压并赋值给多个变量。唯一的前提就是变量的数量必须跟序列元素的数量是一样的

元组的N个元素赋值给N个变量

例:

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

执行结果:

列表的N个元素赋值给N个变量

例:

mlist = ['老大','老二','老三','老四','老五','老六']
a,b,c,d,e,f = mlist
print(a)   #老大
print(c)   #老三
print(e)   #老五

执行结果:

字符串每个元素赋值给N个变量

例:

name = 'PYTHON'
a,b,c,d,e,f = name
print(a)  # P
print(f)  # N

执行结果:

部分元素赋值给部分变量

如果只想要一部份元素,其他元素可丢掉的话,也可以使用此法,占够位置就好了

例:

data = ['老大','老二','老三','老四','老五','老六']
_,_,_,_,e,_ = data
print(e)  #老五

执行结果:

Tips : 这种解压赋值可以用在任何可迭代对象上面,而不仅仅是列表或者元组。包括字符串,文件对象,迭代器和生成器

星号表达式赋值

当一个可迭代对象的元素很多,而你又不愿意写这么多的变量怎么办?星号表达式是不错的选择

例:

family = ['儿子','丈夫','大老婆','二老婆','三老婆','四老婆','五老婆']
son,husband,*wife  =  family
print(son) 
print(wife) 

执行结果:

第二节:保留最后N个元素

使用队collections.deque()保留元素

保留有限的元素正是 collections.deque() 的强项,可用于保存有限的历史记录
使用 deque(maxlen=N) 构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候,最老的元素会自动被移除掉。

例:

from collections import deque

list = ['大老婆', '二老婆', '三老婆', '四老婆', '五老婆']
q = deque(iterable=list,maxlen=2)
print(q)     

q.append('六老婆')
print(q)     #deque(['五老婆', '六老婆'], maxlen=2)

执行结果:

列表两端弹出弹入操作

append() —— 往列表右边添加元素
appendleft() —— 往列表左边添加元素
pop() —— 往列表右边弹出元素
popleft() —— 往列表左边弹出元素

例:

from collections import deque

list = ['大老婆', '二老婆', '三老婆', '四老婆', '五老婆']
q = deque(iterable=list,maxlen=4)
print(q)  
q.append('六老婆')
print(q)    

q.appendleft('七老婆')
print(q)

q.pop()
print(q)     

q.popleft()
print(q)    

执行结果:

第三节:获取列表中最大或最小的N个元素

普通列表中获取最大最小值

nlargest(n,collection) —— 在collection中获取最大的n个元素
nsamllest(n,collection) —— 在collection中获取最小的n个元素

例:

import heapq 
mlist = [-5,9,3,99,27,4,35,0]
#获取列表中最大2个值
print(heapq.nlargest(2,mlist))
#获取列表中最小1个值
print(heapq.nsmallest(1,mlist)) 

执行结果:

列表套字典中获取最大最小值

如果列表套字典的情况,对多个字典的某个键进行比对,函数中需要用到 ‘key=’

例:

dicts = [ 
	{'name':'千里眼','age':11,'RMB':140}, 
	{'name':'顺风耳','age':10,'RMB':170}, 
	{'name':'大力三','age':9,'RMB':90}, 
	{'name':'铜皮四','age':8,'RMB':40}, 
	{'name':'飞天五','age':7,'RMB':180} 
] 
#获取最少钱的2两位 
poorest = heapq.nsmallest(2,dicts,key=lambda r:r['RMB']) 
print(poorest)  

#获取年龄最大的两位 
oldest = heapq.nlargest(2,dicts,key=lambda a:a['age']) 
print(oldest)

执行结果:

第四节:关于字典

一个键对应多个值用元组还是集合

比较:想保持元素的插入顺序用列表,想去掉重复元素用集合
例:

#使用列表
d = {
'a' : [1, 2, 3],
'b' : [4, 5]
}

#使用集合
e = {
'a' : {1, 2, 3},
'b' : {4, 5}
}

构造一个键映射多个值的字典

使用collections.defaultdict()构造字典

例:

from collections import defaultdict 
d = defaultdict(list) 
d['a'].append(1) 
d['a'].append(2) 
d['b'].append(4) 
print(d)  

s = defaultdict(set) 
s['a'].add(1) 
s['a'].add(2) 
s['b'].add(4) 
print(s) 

defaultdict 会自动为将要访问的键 (就算目前字典中并不存在这
样的键) 创建映射实体。若并不需要这样的特性,可以在一个普通的字典上使用setdefault() 方法来代替。

字典的排序和运算

#####控制字典中元素的顺序

控制一个字典中元素的顺序,可以使用 collections 模块中的OrderedDict 类。在迭代操作的时候它会保持元素被插入时的顺序,

例:

from collections import OrderedDict

d = OrderedDict()
d['key1'] = 1
d['key2'] = 2
d['key3'] = 3
d['key4'] = 4
for i in d:
    print(i,d[i])

注:OrderedDict的大小约为字典的2倍,因为它内部维护着另外一个链表。所以遇到大量实例的数据结构时,那么就得仔细权衡是否使用 OrderedDict

字典中求最大最小值、排序
反转键值法求最值:zip() + min() / max()

例:

power = { 
	'达摩祖师':500, 
	'张三疯':300, 
	'扫地神僧':400, 
	'独孤求败':420, 
	'逍遥子':350, 
} 
#求最大值 
print(max(zip(power.values(),power.keys())))  

#求最小值 
print(min(zip(power.values(),power.keys())))
反转键值法求排序字典:zip() + sorted()

例:

power = { 
	'达摩祖师':500, 
	'张三疯':300, 
	'扫地神僧':400, 
	'独孤求败':420, 
	'逍遥子':350, 
} 
#排序 
print(sorted(zip(power.values(),power.keys())))
通过某个关键字排序一个字典

operator.itemgetter() 函数,可以非常容易的排序这样的数据结构

例:

from operator import itemgetter

dictlist = [ 
	{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, 
	{'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, 
	{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, 
	{'fname': 'Big', 'lname': 'Jones', 'uid': 1004} 
] 
 
#按'fname'排序 
sort_fname = sorted(dictlist, key=itemgetter('fname')) 
print(sort_fname) 

#按'uid'排序 
sort_uid = sorted(dictlist, key=itemgetter('uid')) 
print(sort_uid)
  • itemgetter() 函数也支持多个 keys,比如下面的代码
#按'lname'和'fname'进行排序
sort_lfname = sorted(dictlist, key=itemgetter('lname','fname'))
print(sort_lfname)
  • itemgetter() 有时候也可以用 lambda 表达式代替,比如
#按'uid'排序
sort_uid = sorted(dictlist, key=lambda r:r['uid'])
print(sort_uid)

#按'lname'和'fname'排序
sort_lfname = sorted(dictlist, key=lambda k:(k['lname'],k['fname']))
print(sort_lfname)

选择使 用 lambda 函数 或者 是 attrgetter() 可能取决于个人喜好。 但是,attrgetter() 函数通常会运行的快点,并且还能同时允许多个字段进行比较

在两个字典中寻找相同的键或值

  • 使用 “&“ 求相同的元素或键,使用 “-” 求差异化或过滤
a = {'x':1,'y':2,'z':3}
b = {'w':10,'x':11,'y':2}
#相同的键
print(a.keys()&b.keys())    #{'x', 'y'}
#a不同于b的键
print(a.keys()-b.keys())    #{'z'}
#相同的元素
print(a.items()&b.items())  #{('y', 2)}

第五节:序列的其他操作

删除序列相同元素并保持顺序

对列表去重,并保留顺序

例:

def dedupe(items):
    S = set()
    for item in items:
        if item not in S:
            yield item
            S.add(item)
            
            
a = [1, 5, 2, 1, 9, 1, 5, 10]
print(list(dedupe(a)))  #[1, 5, 2, 9, 10]
对字典去重,并保留顺序

例:

def dedupe(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':1, 'y':3},
    {'x':1, 'y':2},
    {'x':2, 'y':4}
]

#'x'键值相同的元素去重
mlist = list(dedupe(a, key=lambda d: (d['x'],d['y'])))
print(mlist)
#[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}}

#'x'和'y'键值都相同的元素进行去重
ylist = list(dedupe(a,key=lambda d : d['x']))
print(ylist)  #[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
对列表简单去重,不考虑元素顺序

例:

mlist = [1,5,3,6,8,0,3,6,8,2,4]
print(set(mlist))
#{0, 1, 2, 3, 4, 5, 6, 8}

给切片命名

例:

word = '9683647163821230739592020257202'

countdays = int(word[11])*int(word[12:14])*int(word[14:16])
print(countdays)  #720

上面的硬编码很难看出谁与谁相乘
此时可使用命名切片优化

word = '9683647163821230739592020257202'
years = slice(11,12)
month = slice(12,14)
days = slice(14,16)

countdays = int(word[years])*int(word[month])*int(word[days])
print(countdays)  #720

tips: 如果你有一个切片对象 s,你可以分别调用它的 s.start , s.stop , s.step 属性来
获取更多的信息。比如:

s = slice(5, 50, 2)
print(s.start)  #5
print(s.stop)  #59
print(s.step)  #2
找出列表中出现次数最多的元素

collections.Counter 类就是专门为这类问题而设计的,它有一个有用的**most common()** 方法,可以解决此问题

例:

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)
print(top_three)      #  [('eyes', 8), ('the', 5), ('look', 4)]

对字典套列表进行分组

使用 itertools.groupby()

例:

dictlist = [
    {'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'}
]

#按'date'排序后分组
from operator import itemgetter
from itertools import groupby

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

以下是打印结果:

07/01/2012
  {'address': '5412 N CLARK', 'date': '07/01/2012'}
  {'address': '4801 N BROADWAY', 'date': '07/01/2012'}
07/02/2012
  {'address': '5800 E 58TH', 'date': '07/02/2012'}
  {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}
  {'address': '1060 W ADDISON', 'date': '07/02/2012'}
07/03/2012
  {'address': '2122 N CLARK', 'date': '07/03/2012'}
07/04/2012
  {'address': '5148 N CLARK', 'date': '07/04/2012'}
  {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}

过滤列表的元素

使用推导式过滤

使用列表推导,这是最简单的方法`

例:

mlist = [1,3,-5,12,-4,2,9,-1]
#过滤负数,只要大于0 的数
print([i for i in mlist if i > 0])    #[1, 3, 12, 2, 9]

#过滤正数,只要小于0 的数
print([i for i in mlist if i < 0])     #[-5, -4, -1]
使用生成器表达式过滤

如果数据比较大,考滤内存因素,可以运用生成器表达式遍历出来
有时候,过滤规则比较复杂,不能简单的在列表推导或者生成器表达式中表达出
来。比如,假设过滤的时候需要处理一些异常或者其他复杂情况。这时候你可以将过
滤代码放到一个函数中,然后使用内建的 filter() 函数。

例:

mlist = ['1', '2', '-3', '-', '4', 'N/A', '5']
#定义一个判断是否数字的方法
def is_int(val):
    try:
        x = int(val)
        return True
    except:
        return False
    
#使用内建函数fillter()过滤    
ret = list(filter(is_int,mlist))
print(ret)         # ['1', '2', '-3', '4', '5']

Tips: filter() 函数只是创建了一个迭代器,想得到一个列表的话,就得使用 list() 去转换。

使用对应的布尔值列表过滤

itertools.compress()
这是以一个 iterable对象和一个相对应的布尔选择器序列作为输入参数。然后输出 iterable 对象中对应选择器为 True 的元素。

例:

mlist = [
    '张三疯',
    '独孤求败',
    '风清扬',
    '达摩祖师',
    '扫地神僧',
    '令狐冲',
    '大理段思平'
]

#定义一个对应的列表
numblist = [1,15,3,4,5,0,13]

from itertools import compress

sorted_list = [n < 10 for n in numblist]
print(sorted_list)   #[True, False, True, True, True, True, False]

#对应着列表过滤
ylist = list(compress(mlist,sorted_list))
print(ylist)        #['张三疯', '风清扬', '达摩祖师', '扫地神僧', '令狐冲']

从字典中提取子集

推导式提取子集

例:

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}
print(p1)    #{'AAPL': 612.78, 'IBM': 205.55}

tech_names = {
	'AAPL',
	'IBM',
	'HPQ',
	'MSFT' 
} 

p2 = {key: value for key, value in prices.items() if key in tech_names}
print(p2)     #{'AAPL': 612.78, 'IBM': 205.55, 'HPQ': 37.2}
使用 dict () 提取子集

创建一个元组序列然后把它传给 dict() 函数也能实现,但速度慢一点点

例:上面例子可如下操作

p1 = dict((key, value) for key, value in prices.items() if value > 200)
print(p1)     #{'AAPL': 612.78, 'IBM': 205.55}

另类法访问列表或元组中元素

collections.namedtuple()
这个函数实际上是一个返回 Python 中标准元组类型子类的一个工厂方法。需要传递一个类型名和字段给它,然后它就会返回一个类,你可以初始化这个类,定义的字段、传递值等。

例:

from collections import namedtuple

#使用namedtuple定义一个类型名和字段
numblist = namedtuple('numblist', ['nb1', 'nb2'])
#为定义好的字段赋值
sub = numblist('bill', 'dicky')
print(sub)  #numblist(nb1='bill', nb2='dicky')
print(sub.nb1)   #bill
print(sub.nb2)   #dicky

namedtuple() 跟一个普通元组,其实没什么两样,是可以正常索引和解压的

print(sub[0])   #bill
nb1,nb2 = sub
print(nb1,nb2)  #bill dicky 

几个优雅方式

计算列表中每个元素的平方和的优雅方式

当在数据序列上执行聚集函数 (比如 sum() , min() , max() ),首先需要先转换或者过滤数据。一个非常优雅的方式去结合数据计算与转换就是使用一个生成器表达式参数。

例:

mlist = [1,2,3,4,5,6]

#正常做法  
ylist = [] 
for i in mlist:     
	k=i*i     
	ylist.append(k) 
print(sum(ylist))    #91 

#更优雅的做法 
print(sum(i*i for i in mlist))   #91
在文件夹中找出py文件的优雅方式
import os 
files = os.listdir('dirname') 

#普通做法 
for filename in files:     
    if filename.endswith('.py'):         
        print('这是一个python文件')     
    else:         
        print('这是其他文件')  
        
#更优雅的做法 
if any(filename.endswith('.py') for filename in files):     
    print('这是一个python文件') 
else:     
    print('这是其他文件') 
字典套列表中找出最小值的优雅方式

例:

tlist = [
    {'name':'GOOG', 'money': 50},
    {'name':'YHOO', 'money': 75},
    {'name':'AOL', 'money': 20},
    {'name':'SCOX', 'money': 65}
]

#一般的做法
hlist = []
for i in tlist:
    k = i['money']
    hlist.append(k)
print(min(hlist))

#更优雅的做法
print(min(s['money'] for s in tlist))

合并多个字典或映射

假如要在一个或多个字典中找查某个键的值可以用 collections.ChainMap(),也可以使用 update() 将字典合并

使用 ChinaMap() 合并字典
a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }
d = {'t': 5, 's': 6 }

#使用 ChinaMap() 合并3个字典
from collections import ChainMap

c = ChainMap(a,b,d)
print(c['x']) # 1 (from a)
print(c['y']) # 2 (from b)
print(c['z']) # 3 (from a)
print(c['s']) # 6 (from d)

一个 ChainMap 接受多个字典并将它们在逻辑上变为一个字典。然后,这些字典并不是真的合并在一起了, ChainMap 类只是在内部创建了一个容纳这些字典的列表并重新定义了一些常见的字典操作来遍历这个列表。大部分字典操作都是可以正常使用的

print(len(c))            #5
print(dict(c))           #{'x': 1, 'z': 3, 't': 5, 's': 6, 'y': 2}
print(list(c.keys()))    #['x', 'z', 't', 's', 'y']
print(list(c.values()))  #[1, 3, 5, 6, 2]
使用 update() 合并字典

例:

a = {'x': 1, 'z': 3 } 
b = {'y': 2, 'z': 4 } 
d = {'t': 5, 's': 6 }  

#使用 update(),合并3个字典
a.update(b) 
a.update(d) 

print(a)        #{'x': 1, 'z': 4, 'y': 2, 't': 5, 's': 6}
print(a['x'])   # 1
print(a['y'])   # 2
print(a['z'])   # 4

【区别】
update() 也能行得通,但是它需要你创建一个完全不同的字典对象 (或者是破坏现有字典结构)。如果此时再对原字典更改键的值,那么也不会反应到新的合并字典中去。’’’

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值