1.可迭代对象中分解元素
这种方式可以很容易的分解参数和产生列表。
>>> a, b, *c = (1,2,3,4,5,6)
>>> a
1
>>> c
[3, 4, 5, 6]
2.队列
简单的队列结构,类似list数据类型。从队列两端添加或弹出元素的时间复杂度为O(1)。而列表从头部插入或移除元素时,时间复杂度为O(N)。与列表类似的数据结构还有array,都比列表性能要好!
from collections import deque
que = deque(maxlen=5) # iter, maxlen
que.appendleft(10)
que.appendleft(8)
que.appendleft(7)
print(que, list(que)) # deque([7, 8, 10], maxlen=5), [7, 8, 10]
que.pop() # 10
que.popleft() # 7
3.找最大,最小的N个元素。
平常是采用max,min来寻找元素,但是只会返回一个元素。
nums = [8, 8, -9, 3, 5, 6, 3, 0]
max_num0 = max(nums, key=lambda x: x < 4) # [False, False, True, True, False, False, True, True]
print(max_num0) # -9
min_num0 = min(nums) #
print(min_num0)
max或者min都可以有一个key参数,当key=x<4,结果是-9,得出这个结果的原因是因为key的结果是Bool值了,max获取最近的那个布尔值,也就是-9.
多个元素采用nlargest()和nsmallest()。
import heapq
max_nums = heapq.nlargest(3, nums)
print(max_nums) # [8, 8, 6]
max_nums2 = heapq.nlargest(3, nums, key=lambda x: x < 4)
print(max_nums2) # [-9, 3, 3]
min_nums = heapq.nsmallest(3, nums)
print(min_nums) # [-9, 0, 2]
dic = [{"book": "java", "price": 66}, {"book": "python", "price": 60}, {"book": "C", "price": 80}]
max_ = heapq.nlargest(2, dic, key=lambda x: x.get('price'))
print(max_) # [{'book': 'C', 'price': 80}, {'book': 'java', 'price': 66}]
PS:
当找最大或最小数据的元素占集合中的总元素数量的比例小时,可以使用heapify()性能更好。
# 堆排序算法
heap = list(nums)
heapq.heapify(heap)
print(heapq.heappop(heap)) # -9
print(heapq.heappop(heap)) # 0
将数组放到堆中排列,由于堆的第一个元素一定是最小的,所以使用heapop()可以方便获取最小元素。算法复杂度(O(logN),N为堆的大小)。
一般来说,对数组进行排序,可以提升性能。
4.优先级队列
class PriorityQueue(object):
def __init__(self):
self._queue = []
self._index = 0
def push(self, item, priority):
heapq.heappush(self._queue, (-priority, self._index, item))
self._index += 1
def pop(self):
return heapq.heappop(self._queue)[-1]
def get_list(self):
return self._queue
if __name__ == '__main__':
q = PriorityQueue()
q.push([1,2,3], 2)
q.push([3,4,5], 5)
q.push([6,7,8], 1)
print(list(q.get_list())) # [(-5, 1, [3, 4, 5]), (-2, 0, [1, 2, 3]), (-1, 2, [6, 7, 8])]
print(q.pop()) # [3, 4, 5]
print(q.pop()) # [1,2,3]
在push元素时,队列会按照优先级进行排序(堆排序,如heapify同样引用了_siftdown方法),在pop时,有总是返回最小的元素。push和pop方法的时间复杂度都为(O(logN))。
def _siftdown(heap, startpos, pos):
newitem = heap[pos]
while pos > startpos:
parentpos = (pos - 1) >> 1
parent = heap[parentpos]
if newitem < parent:
heap[pos] = parent # 交换位置
pos = parentpos
continue
break
heap[pos] = newitem
# [(-2, 0, [1, 2, 3])] 第一次
# [(-5, 1, [3, 4, 5]), (-2, 0, [1, 2, 3])] 2
5.一键多值
创建以下结构的数据,可以使用defaultdict,它可以让你更容易实现。
{
'a': [1,2,3,4,5],
'b': [1,2,3,]
}
{
"a": {1,2,3,4},
"b": {1,3,5}
}
d = defaultdict(list)
d['a'].append(1)
d['a'].append(2)
d['b'].append(3)
dic = defaultdict(set)
dic['c'].add(1)
dic['c'].add(2)
dic['d'].add(3)
dic['c'].add(2)
print(d, dic)
# defaultdict(<class 'list'>, {'a': [1, 2], 'b': [3]}) defaultdict(<class 'set'>, {'c': {1, 2}, 'd': {3}})
6.字典有序
创建一个字典,同时当对字典进行迭代或序列化操作时,可以控制其中元素的顺序。
使用OrderedDict(),当对字典做迭代时,它会严格按照元素初始位置来进行。
from collections import OrderedDict
d = OrderedDict()
d['a'] = 1
d['b'] = 3
d['c'] = 2
d['d'] = 0
for i in d.items():
print(i)
('a', 1)
('b', 3)
('c', 2)
('d', 0)
其内部维护了一个双向链表,它会根据元素加入的顺序来排列键的位置。第一个被放置的元素会被放置在链表的末尾。加下来对已存在的键重新赋值不会改变键的位置。
但是其占用的内存是普通字典的两倍。
7.字典有关的计算
计算字典中元素的最大,最小,排序等
dic = {
"book1": 88,
"book2": 50,
"book3": 66,
"book4": 77
}
print(max(zip(dic.values(), dic.keys()))) # (88, 'book1')
print(min(zip(dic.values(), dic.keys()))) # (50, 'book2')
print(sorted(zip(dic.values(), dic.keys()))) # [(50, 'book2'), (66, 'book3'), (77, 'book4'), (88, 'book1')]
zip()创建一个迭代器,但是其内容只能被消费一次
price_nums = zip(dic.values())
print(max(price_nums))
print(min(price_nums)) # ValueError: min() arg is an empty sequence
提供一个key参数给min()和max(),可以得到最大值和最小值所对应的键。
print(max(dic, key=lambda k: dic[k])) # book1
8.两个字典中寻找相同点
得到两个字典的相同点,可以使用集合的交、并、补集。
x & y # 交集
x | y # 并集
x - y # 差集
# 两字典相同点
dic1 = {'x': 2, "y": 5, "z": 0}
dic2 = {"x": 2, "z": 0, "y": 5, "w": 6}
print(dic1.keys() & dic2.keys()) # 交集
print(dic2.keys() - dic1.keys()) # 差集,dic2和dic1的差集,是dic2中有,但dic1中没有的
print(dic1.items() & dic2.items())
# 结果
{'z', 'y', 'x'}
{'w'}
{('y', 5), ('x', 2), ('z', 0)}
8.字典去重并保留顺序
下面函数中解释了key的作用
def dedupe(items, key=None):
"""该函数模拟了sorted,min,max函数中key的用法"""
seen = set()
for i in items:
val = i if key is None else key(i) # 使用key
if val not in seen:
yield i # 返回生成器
seen.add(val)
a = [{"x":1, "y":2}, {"x": 1, "y":3}, {"x":1, "y":2}, {"x": 2, "y":4}]
dedupe(a, key=lambda d: (d['x'], d['y']))
>>>[{"x":1, "y":2}, {"x":1, "y":2}, {"x": 2, "y":4}]
9.切片命名
例子:对字符串“aadcfeghh ok are you ok?ppfddsfsef”
a = "aadcfeghh ok are you ok?ppfddsfsef"
传统切片:a[13:24]=are you ok?
切片部分可能语义不明
使用slice()
使用slice切片:
word = slice(13, 24)
result = a[word]
print(result) # are you ok?
10.找到序列中出现次数最多的元素
使用Counter类
words = ['a', 'a', 'c', 'bc', 'c', 'b', 'a', 'd', 'a', 'c']
from collections import Counter
counts = Counter(words)
print(counts.most_common(2)) # [('a', 4), ('c', 3)]
由于Counter是一个字典,只是在键值之间作了映射,因此,你可以向操作字典一样,操作它.
print(counts['a'])
如果你希望增加元素,你可以这样做
other_words = ['a', 'b', 'c', 'd']
counts.update(other_words)
print(counts['a']) # 5
Counter可以配合数学运算符来使用
words = ['a', 'a', 'c', 'bc', 'c', 'b', 'a', 'd', 'a', 'c']
from collections import Counter
counts = Counter(words)
other_words = ['a', 'b', 'c', 'd']
new_counts = Counter(other_words)
print(counts - new_counts)
print(counts + new_counts)
# Counter({'a': 4, 'c': 3, 'bc': 1, 'b': 1, 'd': 1})
# Counter({'a': 5, 'c': 4, 'b': 2, 'd': 2, 'bc': 1})
11.对列表中的字典排序
dic = [
{"id": 1001, "name": "bob"},
{"id": 1002, "name": "lilei"},
{"id": 1006, "name": "hmm"},
{"id": 999, "name": "xh"}
]
di = sorted(dic, key=lambda x: x.get('id'))
from operator import itemgetter
di2 = sorted(dic, key=itemgetter('id'))
print(di, di2)
# 结果是相同的,都为:[{'id': 999, 'name': 'xh'}, {'id': 1001, 'name': 'bob'}, {'id': 1002, 'name': 'lilei'}, {'id': 1006, 'name': 'hmm'}]
也就是说lambda与itemgetter的实现是类似的,但是itemgetter()的性能更高,这在max()和min()中同样适用,并且itemgetter()可以传du多个字段。
12.对对象进行排序
class User(object):
def __init__(self, user_id):
self.user_id = user_id
def __repr__(self):
return 'user id : {}'.format(self.user_id)
users = [User(3), User(0), User(6)]
from operator import attrgetter
print(sorted(users, key=attrgetter('user_id')))
# [user id : 0, user id : 3, user id : 6]
13.对数据进行分组
rows = [
{"address": 'beijing', "date": "2020/7/1", "weather": "晴天"},
{"address": 'shanghai', "date": "2020/7/1", "weather": "晴天"},
{"address": 'beijing', "date": "2020/6/30", "weather": "多云"},
{"address": 'wuhan', "date": "2020/7/1", "weather": "晴天"},
{"address": 'wuhan', "date": "2020/6/29", "weather": "暴雨"},
]
from operator import itemgetter
from itertools import groupby
rows.sort(key=itemgetter('date')) # 必须排序
print(groupby(rows, key=itemgetter('date'))) # 可迭代对象,内部结构是元组
for date, items in groupby(rows, key=itemgetter('date')):
print(date)
for i in items:
print(' ', i)
# 2020/6/29
{'address': 'wuhan', 'date': '2020/6/29', 'weather': '暴雨'}
2020/6/30
{'address': 'beijing', 'date': '2020/6/30', 'weather': '多云'}
2020/7/1
{'address': 'beijing', 'date': '2020/7/1', 'weather': '晴天'}
{'address': 'shanghai', 'date': '2020/7/1', 'weather': '晴天'}
{'address': 'wuhan', 'date': '2020/7/1', 'weather': '晴天'}
14.筛选序列中的元素
通常筛选元素采用列表推导式,可以简单且优雅的筛选元素。但是如果,结果过于庞大,可能会让电脑死机(亲身体验)。可以使用生成器解决这个问题。
def filter_item():
"""从数量集1000万中筛选小于50的数"""
nums = [i for i in range(10000000)]
items = (n for n in nums if n < 50)
print(list(items))
如果还需要处理复杂逻辑时,可以使用filter(func, iter)
print(list(filter(lambda x: x < 50, nums)))
15.将名称映射到序列化的元素中
使用类似对象.属性的方式来获取数据。可以采用collections.namedtuple()(命名元组)来为我们提供便利。
>>> from collections import namedtuple
>>> Sub = namedtuple('Subsc', ['addr', 'joined'])
>>> sub = Sub('hubei', '2012')
>>> sub.addr
'hubei'
>>> sub
Subsc(addr='hubei', joined='2012')
支持拆包addr, joined = sub
,namedtuple是不可变的类型,这一点与tuple相同。
如果,你需要修改属性的值,你可以使用_replace()修改
sub = sub._replace(addr='beijing')
16.多个映射合并为一个映射
将多个字典或者映射,在逻辑上合并为一个单独的映射结构,以执行特定的操作,比如查找值或者检查键是否存在。
>>> a = {'x': 1, 'y': 2}
>>> b = {'y': 4, 'z': 4}
>>> from collections import ChainMap
>>> c = ChainMap(a, b)
>>> c
ChainMap({'x': 1, 'y': 2}, {'y': 4, 'z': 4})
>>> c['x']
1
>>> c['w']
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
c['w']
File "C:\Python\lib\collections\__init__.py", line 916, in __getitem__
return self.__missing__(key) # support subclasses that define __missing__
File "C:\Python\lib\collections\__init__.py", line 908, in __missing__
raise KeyError(key)
KeyError: 'w'
>>> c['y']
2
如果有值就会返回结果否则报错。
ChainMap并不是合并字典,而是简单的维护一个记录底层映射关系的列表,然后重定义常见字典操作来扫描这个列表。
如果有重复的键,会优先采用第一个映射对应的值。
评论列表
已有0条评论