下面是一些python中常见的数据结构知识点总结,还有一些编程小技巧分享给大家
字典元组列表等数据结构
- 一个键对应单一的映射,若想一个键对应多个值,需要将多个值放入容器中,可以是列表或是集合
- 若不关心元素的顺序,并且元素不重复的话,可以使用集合
- 若在乎添加的顺序可使用列表
defaultdict模块
defaultdict模块可以在初始化时,就将key的类型固定,只需关注修改的一些操作即可
from collections import defaultdict d=defaultdict(list) d['a'].append('1') d['b'].append('2') d_=defaultdict(set) d_['a'].add('1') d_['b'].add('2') dct=defaultdict(list) pairs=['a','b','c','d'] for key,value in paires: dct[key].append(value) return dct print(d) print(d_)
使用defaultdict可以快速创建一个字典映射
OrderdeDIct模块
from collections import OrderedDict def ordered_dict(): d = OrderedDict() d['foo'] = 1 d['bar'] = 2 d['spam'] = 3 d['grok'] = 4 # Outputs "foo 1", "bar 2", "spam 3", "grok 4" for key in d: print(key, d[key]) ordered_dict()
- OrderedDict函数可以保存字典的存入顺序,返回顺序字典
- OrderedDict函数内部有一个双向链表,控制元素的插入顺序,当一个元素插入时,默认添加到尾部,对于一个存在的键的重复复置不会改变键的顺序
- OrderedDict函数的创建对象比普通字典大两倍,因为内部链表的原因,所以当创建时,要权衡内存占用情况
字典的运算
prices = { 'ACME': 45.23, 'AAPL': 612.78, 'IBM': 205.55, 'HPQ': 37.20, 'FB': 10.75 } min_price=min(zip(prices.values(),prices.keys())) max_price=max(zip(prices.values(),prices.keys())) print(min_price,max_price) sort_dct=sorted(zip(prices.values(),prices.keys())) print(sort_dct) print(type(sort_dct)) '''显示结果如下: (10.75, 'FB') (612.78, 'AAPL') [(10.75, 'FB'), (37.2, 'HPQ'), (45.23, 'ACME'), (205.55, 'IBM'), (612.78, 'AAPL')] <class 'list'>'''
- 字典的运算取值(最大或最小)可使用zip函数进行
- 可以使用sorted函数对字典进行排序
- 当字典中出现不同的键对应相同的值时,会比较键的大小来返回结果
比较字典
a = {'x' : 1, 'y' : 2, 'z' : 3 } b = {'w' : 10, 'x' : 11, 'y' : 2 } # Find keys in common 交集 a.keys() & b.keys() # { 'x', 'y' } # Find keys in a that are not in b 差集 a.keys() - b.keys() # { 'z' } # Find (key,value) pairs in common 键值对交集 a.items() & b.items() # { ('y', 2) }
- 可以简单的使用集合操作符来比较两个字典键值对的异同点
- 集合的键支持集合操作,若想对键集合执行一些几个操作可以先转换成set,同理值集合也一样
删除序列相同元素并保持顺序
def setone(item): seen=set() for element in item: if element not in seen: yield element seen.add(element)
- 当序列中的元素可hasnable时,可以使用生成器和集合的方式实现
当序列不可hashable时
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}]'''
- 需要先将序列转换为可hashable的再来过滤
命名切片
record='123456789012345678901234567890123456789012345678901234567890' SHARES = slice(20, 23) PRICE = slice(31, 37) cost = int(record[SHARES]) * float(record[PRICE]) print(cost) items = [0, 1, 2, 3, 4, 5, 6] a=slice(2,4,2) print(type(a)) print(items[a]) print(a.start) print(a.stop) print(a.step) a=slice(5,50,2) s='HelloWorld' print(type(a.indices(len(s)))) #a.indices()函数返回元组对象(start,stop,step)三元组 for i in range(*a.indices(len(s))): print(s[i])
- slice函数创建切片对象,可以slice任何支持切片操作的对象
- 可以调用slice函数创建的切片对象方法start,stop,step属性进一步查看相关信息
- slice创建的对象方法indices可以划定边界长度,使创建的对象长度固定
查找序列中出现次数最多的元素
from collections import Counter 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' ] word_counts = Counter(words) #创建Counter对象 top_three = word_counts.most_common(3) #打印出现频率最高的三个单词,使用most_common()函数 print(top_three) # Outputs [('eyes', 8), ('the', 5), ('look', 4)] from collections import Counter 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' ] morewords = ['why','are','you','not','looking','in','my','eyes'] a=Counter(words) b=Counter(morewords) c=a+b print(len(c)) d=a-b print(d)
- most_common()函数返回出现次数最多的元素
- Counter的对象可以直接进行数学运算操作
通过某个关键词排序字典列表
from operator import itemgetter rows = [ {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} ] rows_by_lname=sorted(rows,key=itemgetter('lname')) rows_by_uid=sorted(rows,key=itemgetter('uid')) #itemgetter函数可添加多个参数itemgetter('fname','lname') rows_by_fname = sorted(rows, key=lambda r: r['fname']) rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname'])) min(rows, key=itemgetter('uid')) max(rows, key=itemgetter('uid')) print(rows_by_uid) print(rows_by_lname)
- operator模块的函数itemgtter()可以实现按照某个字典键排序字典列表
- itemgetter可以使用lambda函数替换,但是itemgetter函数运行更快
- 如果数据较少,且要返回单一最值,可使用max和min函数
排序不支持原生对象的解决
class User(): def __init__(self,user_id): self.user_id=user_id def __repr__(self): return f'User({self.user_id})' def sort_one(): users=[User(32),User(12),User(50)] user_sort=sorted(users,key=lambda u:u.user_id) return user_sort #—————————————————————————————— from operator import attrgetter sorted(users, key=attrgetter('user_id')) by_name = sorted(users, key=attrgetter('last_name', 'first_name')) min(users, key=attrgetter('user_id') max(users, key=attrgetter('user_id')
- sorted()函数的key参数,接受一个callable对象,callable对象返回其中的值,sorted函数根据返回的值对序列进行排序
- 还可以使用attrgetter模块,接受排序依据参数,进行序列的排序
- attrgetter要比lambda函数稍微快一些,且可以支持多个参数
- attrgetter同样适用于max和min函数
通过某个字段为记录分组
from operator import itemgetter from itertools import groupby rows = [ {'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'}, ] rows.sort(key=itemgetter('date')) for date,item in groupby(rows,key=itemgetter('date')): print(date) for i in item: print(i) from collections import defaultdict rows_by_date = defaultdict(list) for row in rows: rows_by_date[row['date']].append(row) for r in rows_by_date['07/01/2012']: print(r) '''显示结果如下: 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'}'''
- itertools中的groupby可以根据传进来的key参数,分组排序
- groupby函数扫描整个序列并查找相同连续值返回一个对象和迭代器,注意迭代器返回的是上述传进参数的键有着相同的值的所有对象元素集合
- 若只想将某个字段放进新的数据结构中,可使用defauledict,若不关心排序问题,运行的比先排序后groupby快一些
过滤(除了使用列表推导,生成器表达式)
values = ['1', '2', '-3', '-', '4', 'N/A', '5'] def is_int(val): try: x = int(val) return True except ValueError: return False ivals = list(filter(is_int, values)) print(ivals) from itertools import compress 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', ] count=[3,4,5,2,5,6,7] more=[n>5 for n in count] new=list(compress(addresses,more)) print(new)
- 使用filter函数可以处理复杂情况的过滤
- 使用推导式的时候,可以将过滤掉的元素更改,或将筛选出的元素更改,通过增加控制条件即可
- 使用compress函数:首先需要一个Boolean序列对象,再将需要过滤的元素放进,按位置的True,False过滤出True的序列对象
- compress函数返回的是一个迭代器对象,可以做进一步转换
namedtuple的实例参数的替换
from collections import namedtuple Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time']) stock_prototype = Stock('', 0, 0.0, None, None) # Create a prototype instance def dict_to_stock(s): # Function to convert a dictionary to a Stock return stock_prototype._replace(**s) #接受一个字典 a = {'name': 'ACME', 'shares': 100, 'price': 123.45} b = {'name': 'ACME', 'shares': 100, 'price': 123.45, 'date': '12/17/2012'} print(dict_to_stock(a)) print(dict_to_stock(b))
- _replace方法替换创建的命名元组实例的属性
- 若想在刚创建时,预留一些参数不设定即可使用此方法,再使用replace方法替换即可
合并多个字典
使用ChainMap模块
from collections import ChainMap a = {'x': 1, 'z': 3 } b = {'y': 2, 'z': 4 } c = ChainMap(a,b) print(c['x']) # Outputs 1 (from a) print(c['y']) # Outputs 2 (from b) print(c['z']) # Outputs 3 (from a) merged = dict(b) merged.update(a) print(merged)
- ChainMap接受字典参数并在其内部创建一个包含字典的列表,并重新定义了一些字典操作来遍历列表,大部分的字典操作都是支持的
- 若在ChainMap中出现相同的键时,键的值和第一个字典中的键的值一致
- 对于ChainMap创建的实例对象的修改操作,会影响到第一个合并的字典的内容
- update函数也是合并字典,若两个字典中有相同的键,则更新键值,对原字典的操作,不会影响到合并的字典的内容
- 注意对于ChainMap生成的字典,若对原字典进行修改,则会影响到合并的字典,因为ChainMap不会创建新的字典
好啦这就是关于python中的数据结构的一些方法与属性的阐述啦!希望对大家有所帮助