1.将序列分解为单独的变量

任何的序列(或者是可迭代对象)可以通过一个简单的赋值操作来分解为单独的变量。 唯一的要求就是变量的总数和结构必须与序列相吻合。

如果元素的数量不匹配,会得到一个错误提示

示例如下:

>>> p = (4, 5)
>>> x, y = p
>>> x
4
>>> y
5
>>>
>>> data = [ 'CSDN', 50, 91.1, (2022, 4, 14) ]
>>> name, shares, price, date = data
>>> name
'CSDN'
>>> date
(2022, 4, 14)
>>> name, shares, price, (year, mon, day) = data
>>> name
'CSDN'
>>> year
2022
>>> mon
4
>>> day
14
>>>

如果只想解压其中一部分,丢弃其他的值。对于这种情况 Python 并没有提供特殊的语法。 但是可以使用任意变量名去占位,到时候丢掉这些变量就行了

注意:占位所用变量名必须保证不会在代码其他地方二次使用

示例如下:

>>> data = [ 'CSDN', 50, 91.1, (2022, 4, 14) ]
>>> _, shares, price, _ = data
>>> shares
50
>>> price
91.1
>>>

2.解压可迭代对象赋值给多个变量

上一节中将可迭代对象进行逐个分解赋值给对应变量,如果一个可迭代对象的元素个数超过变量个数时,会抛出一个 ValueError 。 通过星号表达式能从这个可迭代对象中解压出 N 个元素出来。

>>> record = ('Dave', 'dave@example.com', '773-555-1212', '847-555-1212')
>>> name, email, *phone_numbers = record
>>> name
'Dave'
>>> email
'dave@example.com'
>>> phone_numbers
['773-555-1212', '847-555-1212']
>>>

注意的是上面解压出的 phone_numbers 变量永远都是列表类型,不管解压的电话号码数量是多少(包括 0 个)。

应用(1):星号表达式在迭代元素为可变长元组的序列时

records = [('foo', 1, 2),('bar', 'hello'),('foo', 3, 4),
]def do_foo(x, y):print('foo', x, y)def do_bar(s):print('bar', s)for tag, *args in records:if tag == 'foo':do_foo(*args)elif tag == 'bar':do_bar(*args)

应用(2) 字符串分割

>>> line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false'
>>> uname, *fields, homedir, sh = line.split(':')
>>> uname
'nobody'
>>> homedir
'/var/empty'
>>> sh
'/usr/bin/false'
>>>

应用(3)实现递归

>>> def sum(items):
...     head, *tail = items  #星号表达式记录 除第一个元素外 后续所有元素
...     return head + sum(tail) if tail else head #进行递归操作 直至后续只剩唯一头元素则结束递归
...
>>> sum(items)
36
>>>

3.保留最后 N 个元素

使用 deque(maxlen=N) 构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候, 最老的元素会自动被移除掉。

>>> q = deque(maxlen=3)
>>> q.append(1)
>>> q.append(2)
>>> q.append(3)
>>> q
deque([1, 2, 3], maxlen=3)
>>> q.append(4)
>>> q
deque([2, 3, 4], maxlen=3)
>>> q.append(5)
>>> q
deque([3, 4, 5], maxlen=3)

应用:匹配历史记录最后N行

from collections import dequedef search(lines, pattern, history=5):previous_lines = deque(maxlen=history)for line in lines:if pattern in line:yield line, previous_linesprevious_lines.append(line)# Example use on a file
if __name__ == '__main__':with open(r'../../cookbook/somefile.txt') as f:for line, prevlines in search(f, 'python', 5):for pline in prevlines:print(pline, end='')print(line, end='')print('-' * 20)

4.查找最大或最小的 N 个元素

借助heapq模块 从一个集合中获得最大或者最小的 N 个元素列表

import heapq
portfolio = [{'name': 'IBM', 'shares': 100, 'price': 91.1},{'name': 'AAPL', 'shares': 50, 'price': 543.22},{'name': 'FB', 'shares': 200, 'price': 21.09},{'name': 'HPQ', 'shares': 35, 'price': 31.75},{'name': 'YHOO', 'shares': 45, 'price': 16.35},{'name': 'ACME', 'shares': 75, 'price': 115.65}
]
cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
print(cheap)
print(expensive) 

结果:

[{'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}]
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'IBM', 'shares': 100, 'price': 91.1}]

heapq模块底层实现通过建立最小堆排序完成

>>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
>>> import heapq
>>> heap = list(nums)
>>> heapq.heapify(heap) #heapq将list转化为堆排序
>>> heap
[-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8]
>>>

堆数据结构最重要的特征是 heap[0] 永远是最小的元素。并且剩余的元素可以很容易的通过调用 heapq.heappop() 方法得到, 该方法会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素(这种操作时间复杂度仅仅是 O(log N),N 是堆大小)。 比如,如果想要查找最小的 3 个元素可以:

>>> heapq.heappop(heap)
-4
>>> heapq.heappop(heap)
1
>>> heapq.heappop(heap)
2

注意:

(1)当要查找的元素个数相对比较小的时候,函数 nlargest() 和 nsmallest() 是很合适的。

(2)如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用 min() 和 max() 函数会更快

(3)如果 N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点 ( sorted(items)[:N] 或者是 sorted(items)[-N:] )。

5.实现一个优先级队列

heapq功能:

heappush(heap,item) heap为堆  item为新增加元素
heapify(list) 将列表转换为堆
heappop(heap) 删除堆第一个元素,堆第一个元素heap[0]为最小值,即删除并返回最小值
heapreplace(heap,item) 删除并返回最小元素,添加新元素
heappushpop(list,item) 新添加元素与堆第一个元素对比:如果大,则删除并返回第一个元素,然后添加新元素 ;如果小,返回新元素,原堆不变
merge(heap1,heap2...) 多个堆合并
nlargest(n,heap) 查询堆中最大n个元素
nsmallest(n,heap) 查询堆中最小n个元素

优先级队列:

class PriorityQueue:def __init__(self):self.__queue = []self.__index = 0def push(self, item, priority):heapq.heappush(self.__queue, (-priority, self.__index, item))# 第一个参数:添加进的目标序列# 第二个参数:将一个元组作为整体添加进序列,目的是为了方便比较# 在priority相等的情况下,比较_index# priority为负数使得添加时按照优先级从大到小排序,因为堆排序的序列的第一个元素永远是最小的self.__index += 1def pop(self):# 返回按照-priority 和 _index 排序后的第一个元素(是一个元组)的最后一个元素(item)return heapq.heappop(self.__queue)[-1]q = PriorityQueue()
q.push("bar", 2)
q.push("foo", 1)
q.push("gork", 3)
q.push("new", 1)
print(q.pop())
print(q.pop())
print(q.pop())
print(q.pop())"""
gork  # 优先级最高
bar   # 优先级第二
foo   # 优先级与new相同,比较index,因为先加入,index比new小,所以排在前面
new
"""

6.字典中的键映射多个值

一个字典就是一个键对应一个单值的映射。如果想要一个键映射多个值,就需要将这多个值放到另外的容器中, 比如列表或者集合里面。

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

使用 collections 模块中的 defaultdict 来构造这样的字典

from collections import defaultdictd = defaultdict(list)
d['a'].append(1)
d['a'].append(2)
d['b'].append(4)##结果
defaultdict(, {'a': [1, 2], 'b': [4]})

创建一个多值映射字典:普通方法与 defaultdict 方法比较

d = {}
for key, value in pairs:if key not in d:d[key] = []d[key].append(value)#**********************************d = defaultdict(list)
for key, value in pairs:d[key].append(value)

7.字典排序

为了能控制一个字典中元素的顺序,你可以使用 collections 模块中的 OrderedDict 类。 在迭代操作的时候它会记录插入字典的顺序  之后再对该字典进行插入的键值保持元素被插入时的顺序.

OrderedDict 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候, 它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会改变键的顺序

from collections import OrderedDictd = 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])d['baidu'] = 3
d['tencent'] = 4
# Outputs "foo 1", "bar 2", "spam 3", "grok 4", "baidu 3", "tencent 4"
for key in d:print(key, d[key])

注意:

一个 OrderedDict 的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。 所以如果你要构建一个需要大量 OrderedDict 实例的数据结构的时候(比如读取 100,000 行 CSV 数据到一个 OrderedDict 列表中去), 那么就得仔细权衡一下是否使用 OrderedDict 带来的好处要大过额外内存消耗的影响

8.字典的运算

如果你在一个字典上执行普通的数学运算,你会发现它们仅仅作用于键,而不是值

zip() 函数方案通过将字典”反转”为 (值,键) 元组序列来解决了上述问题。 当比较两个元组的时候,值会先进行比较,然后才是键。

prices = {'ACME': 45.23,'AAPL': 612.78,'IBM': 205.55,'HPQ': 37.20,'FB': 10.75
}min_price = min(zip(prices.values(), prices.keys()))
# min_price is (10.75, 'FB')
max_price = max(zip(prices.values(), prices.keys()))
# max_price is (612.78, 'AAPL')min(prices, key=lambda k: prices[k]) # Returns 'FB'
max(prices, key=lambda k: prices[k]) # Returns 'AAPL'

9.查找两字典的相同点

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) }

(1)一个字典就是一个键集合与值集合的映射关系。 字典的 keys() 方法返回一个展现键集合的键视图对象。 支持集合操作,比如集合并、交、差运算。 所以,如果对集合的键执行一些普通的集合操作,可以直接使用键视图对象而不用先将它们转换成一个 set。

(2)字典的 items() 方法返回一个包含 (键,值) 对的元素视图对象。 这个对象同样也支持集合操作,并且可以被用来查找两个字典有哪些相同的键值对。

(3)尽管字典的 values() 方法也是类似,但是它并不支持这里介绍的集合操作。 某种程度上是因为值视图不能保证所有的值互不相同,这样会导致某些集合操作会出现问题。 不过,如果非要在值上面执行这些集合操作的话,你可以先将值集合转换成 set,然后再执行集合运算就行了。

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

如何在一个序列上面保持元素顺序的同时消除重复的值

set集合方法不能维护元素的顺序,生成的结果中的元素位置被打乱

(1)非字典元素

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

(2)字典元素

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 itemseen.add(val)#这里的key参数指定了一个函数,将序列元素转换成 hashable 类型>>> 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}]
>>> list(dedupe(a, key=lambda d: d['x']))
[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
>>>

11.命名切片

内置的 slice() 函数创建了一个切片对象

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11] #切片部分赋新值
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]

通过调用切片的 indices(size) 方法将它映射到一个已知大小的序列上。 这个方法返回一个三元组 (start, stop, step) ,所有的值都会被缩小,直到适合这个已知序列的边界为止。 这样,使用的时就不会出现 IndexError 异常

>>> s = 'HelloWorld'
>>> a.indices(len(s))
(5, 10, 2)
>>> for i in range(*a.indices(len(s))):
...     print(s[i])
...
W
r
d

12.序列中出现次数最多的元素

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

一个 Counter 对象底层实现就是一个字典,将需要统计的元素映射到它统计的次数上

>>> word_counts['not']
1
>>> word_counts['eyes']
8
>>>

13.通过某个关键字排序一个字典列表

通过使用 operator 模块的 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}
]from operator import itemgetter
rows_by_fname = sorted(rows, key=itemgetter('fname'))
rows_by_uid = sorted(rows, key=itemgetter('uid'))
print(rows_by_fname)
print(rows_by_uid)'''
#结果
[{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'},
{'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'},
{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},
{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'}][{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'},
{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},
{'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'},
{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'}]
'''rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
print(rows_by_lfname)'''
#结果
[{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},
{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'},
{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'},
{'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'}]
'''

itemgetter() 有时候也可以用 lambda 表达式代替,比如:

#根据lambda表达式中字典key值进行索引排序rows_by_fname = sorted(rows, key=lambda r: r['fname'])
rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))

14.排序不支持原生比较的对象

使用 operator.attrgetter() 来完成

class User:def __init__(self, user_id):self.user_id = user_iddef __repr__(self):return 'User({})'.format(self.user_id)users = [User(23), User(3), User(99)]
print(users)
print(sorted(users, key=lambda u: u.user_id))'''
#结果
[User(23), User(3), User(99)]
[User(3), User(23), User(99)]'''from operator import attrgetter
print(sorted(users, key=attrgetter('user_id')))'''
#结果
[User(3), User(23), User(99)]'''

15.通过某个字段将记录分组

itertools.groupby() 函数对于这样的数据分组操作非常实用

现在假设你想在按 date 分组后的数据块上进行迭代。为了这样做,你首先需要按照指定的字段(这里就是 date进行排序, 然后调用 itertools.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'},
]from operator import itemgetter
from itertools import groupby# Sort by the desired field first
rows.sort(key=itemgetter('date'))
# Iterate in groups
for date, items in groupby(rows, 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'}'''

groupby() 函数扫描整个序列并且查找连续相同值(或者根据指定 key 函数返回值相同)的元素序列。一个非常重要的准备步骤是要根据指定的字段将数据排序。 因为 groupby() 仅仅检查连续的元素,如果事先并没有排序完成的话,分组函数将得不到想要的结果

16.过滤序列元素

最简单的方法:列表推导

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> [n for n in mylist if n > 0]
[1, 4, 10, 2, 3]
>>> [n for n in mylist if n < 0]
[-5, -7, -1]
>>>

过滤并替换

mylist = [1, 4, -5, 10, -7, 2, 3, -1]
clip_neg = [n if n > 0 else 0 for n in mylist]
print(clip_neg)clip_pos = [n if n < 0 else 0 for n in mylist]
print(clip_pos)'''
#结果
[1, 4, 0, 10, 0, 2, 3, 0]
[0, 0, -5, 0, -7, 0, 0, -1]'''

有时候,过滤规则比较复杂,不能简单的在列表推导或者生成器表达式中表达出来。 比如,假设过滤的时候需要处理一些异常或者其他复杂情况。这时候可以使用内建的 filter() 函数。

values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):try:x = int(val)return Trueexcept ValueError:return False
ivals = list(filter(is_int, values))
print(ivals)
# Outputs ['1', '2', '-3', '4', '5']

另外一个过滤工具就是 itertools.compress() , 它以一个 iterable 对象和一个相对应的 Boolean 选择器序列作为输入参数。 然后输出 iterable 对象中对应选择器为 True 的元素。

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',
]
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]>>> from itertools import compress
>>> more5 = [n > 5 for n in counts]
>>> more5
[False, False, True, False, False, True, True, False]
>>> list(compress(addresses, more5))
['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']
>>>

17.从字典中提取子集

(1)字典推导

prices = {'ACME': 45.23,'AAPL': 612.78,'IBM': 205.55,'HPQ': 37.20,'FB': 10.75
}
# Make a dictionary of all prices over 200
p1 = {key: value for key, value in prices.items() if value > 200}
print(p1)
'''
#结果
{'AAPL': 612.78, 'IBM': 205.55}
'''# Make a dictionary of tech stocks
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}
'''

(2)dict()函数

prices = {'ACME': 45.23,'AAPL': 612.78,'IBM': 205.55,'HPQ': 37.20,'FB': 10.75
}
# Make a dictionary of all prices over 200
#p1 = {key: value for key, value in prices.items() if value > 200}
p1 = dict((key, value) for key, value in prices.items() if value > 200)print(p1)'''
#结果
{'AAPL': 612.78, 'IBM': 205.55}
'''# Make a dictionary of tech stocks
tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}
#p2 = {key: value for key, value in prices.items() if key in tech_names}
p2=dict((key, value)for key, value in prices.items() if key in tech_names)
print(p2)
'''
#结果
{'AAPL': 612.78, 'IBM': 205.55, 'HPQ': 37.2}
'''

18.映射名称到序列元素

即所谓,通过名称而不是通过下标访问元素

命名元组访问:

>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriber(addr='jonesy@example.com', joined='2012-10-19')
>>> sub.addr
'jonesy@example.com'
>>> sub.joined
'2012-10-19'
>>>>>> len(sub)
2
>>> addr, joined = sub
>>> addr
'jonesy@example.com'
>>> joined
'2012-10-19'
>>>

命名元组的一个主要用途是将你的代码从下标操作中解脱出来。 下标操作通常会让代码表意不清晰,并且非常依赖记录的结构,但是如果你使用了命名元组,那么就不会有这样的顾虑。

def compute_cost(records):total = 0.0for rec in records:total += rec[1] * rec[2]#存储结构为一个很大的元组列表,通过下标去操作其中的元素, 当你在结构中添加了新的列的时候你的代码可能就会出错了return totalfrom collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def compute_cost(records):total = 0.0for rec in records:s = Stock(*rec)total += s.shares * s.pricereturn total

命名元组如果需要改变属性的值,使用_replace() 方法进行替换或填充数据

>>> s = s._replace(shares=75)
>>> s
Stock(name='ACME', shares=75, price=123.45)
>>>from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])
# Create a prototype instance
stock_prototype = Stock('', 0, 0.0, None, None)
# Function to convert a dictionary to a Stock
def dict_to_stock(s):return stock_prototype._replace(**s)
>>> a = {'name': 'ACME', 'shares': 100, 'price': 123.45}
>>> dict_to_stock(a)
Stock(name='ACME', shares=100, price=123.45, date=None, time=None)
>>> b = {'name': 'ACME', 'shares': 100, 'price': 123.45, 'date': '12/17/2012'}
>>> dict_to_stock(b)
Stock(name='ACME', shares=100, price=123.45, date='12/17/2012', time=None)
>>>

19.转换并同时计算数据

nums = [1, 2, 3, 4, 5]
s = sum(x * x for x in nums)
print(s)'''
55
'''portfolio = [{'name':'GOOG', 'shares': 50},{'name':'YHOO', 'shares': 75},{'name':'AOL', 'shares': 20},{'name':'SCOX', 'shares': 65}
]
min_shares = min(s['shares'] for s in portfolio)
print(min_shares)'''
20
'''

20.合并多个字典或映射

现在有多个字典或者映射,想将它们从逻辑上合并为一个单一的映射后执行某些操作, 比如查找值或者检查某些键是否存在。

a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }

现在假设你必须在两个字典中执行查找操作(比如先从 a 中找,如果找不到再在 b 中找)。 一个非常简单的解决方案就是使用 collections 模块中的 ChainMap 类。

from collections import ChainMap
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) 如果出现重复键,那么第一次出现的映射值会被返回。 因此,例子程序中的 c['z'] 总是会返回字典 a 中对应的值,而不是 b 中对应的值。

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

>>> len(c)
3
>>> list(c.keys())
['x', 'y', 'z']
>>> list(c.values())
[1, 2, 3]
>>>

对于字典的更新或删除操作总是影响的是列表中第一个字典

>>> c['z'] = 10 #修改a中'z'的值
>>> c['w'] = 40 #向a中添加新值‘w’
>>> del c['x']  #删除a中'x'的值
>>> a
{'w': 40, 'z': 10}
>>> del c['y']  #不会修改第二个字典  则报错返回
Traceback (most recent call last):
...
KeyError: "Key not found in the first mapping: 'y'"
>>>

注意:ChainMap不同与使用 update() 方法将两个字典合并,update建立一个新字典作为合并字典进行存储,原字典的修改不会影响合并字典

Python(一)数据结构和算法相关推荐

  1. Python版本的数据结构书_《用Python解决数据结构与算法问题》

    源于经典 数据结构作为计算机从业人员的必备基础,Java, c 之类的语言有很多这方面的书籍,Python 相对较少, 其中比较著名的一本 problem-solving-with-algorithm ...

  2. python中文教程github_GitHub - Virile-Tao/python_data_structures_and_algorithms: Python 中文数据结构和算法教程...

    Python 算法与数据结构视频教程 课程简介 数据结构和算法是每个程序员需要掌握的基础知识之一,也是面试中跨不过的槛.目前关于 Python 算法和数据结构的系统中文资料比较欠缺, 笔者尝试录制视频 ...

  3. 【python版本数据结构与算法】基本概念(10-1)

    参考书: <数据结构与算法(Python语言描述)> 最原始的方法:枚举法 那么数据结构和算法是什么?答曰:兵法! 我们可以不看兵法在战场上肉搏,如此,可能会胜利,可能会失败.即使胜利,可 ...

  4. python数据结构教程_GitHub - Frank-Jing/python_data_structures_and_algorithms: Python 中文数据结构和算法教程...

    Python 算法与数据结构视频教程 课程简介 数据结构和算法是每个程序员需要掌握的基础知识之一,也是面试中跨不过的槛.目前关于 Python 算法和数据结构的系统中文资料比较欠缺, 笔者尝试录制视频 ...

  5. 【python】数据结构和算法 + 浅谈单链表与双链表的区别

    有这么一句话说"程序=数据结构+算法",也有人说"如果把编程比作做菜,那么数据结构就好比食材(菜),算法就好比厨艺(做菜的技巧)". 当然这是笼统的说法,不过也 ...

  6. 用Python解决数据结构与算法问题(一):Python基础

    python学习之路 - 从入门到精通到大师 文章目录 [python学习之路 - 从入门到精通到大师](https://blog.csdn.net/TeFuirnever/article/detai ...

  7. python【数据结构与算法】深入浅出哈希表

    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列 ...

  8. python【数据结构与算法】计数问题(分治)

    文章目录 1 算法描述 2 实现 3 复杂度 1 算法描述 题目:给定n个整数的数组A以及一个数x,设计一个分治算法,求出x在数组中出现的次数,并分析时间复杂度. 算法思想: 分:先将问题划分为大小近 ...

  9. python【数据结构与算法】最小生成树之Kruskal算法

    我们用现在来模拟一下Kruskal算法,下面给出一个无向图B,我们使用Kruskal来找无向图B的最小生成树. 首先,我们将所有的边都进行从小到大的排序.排序之后根据贪心准则,我们选取最小边(A,D) ...

  10. python【数据结构与算法】最长公共子串详解(附代码)

    文章目录 1 定义 1 定义 和最长公共子序列一样,使用动态规划的算法. 下一步就要找到状态之间的转换方程. 和LCS问题唯一不同的地方在于当A[i] != B[j]时,res[i][j]就直接等于0 ...

最新文章

  1. GAC中部署assembly的问题总结
  2. Python入门图文解说
  3. STM32 F101系列的程序怎么转化为STM F103出现编译错误!
  4. 将EntityManager.refresh添加到所有Spring数据存储库
  5. 3种团队分组适应项目_团队类型
  6. php处理上传文件的步骤,php文件上传步骤
  7. 瑞士军刀Netcat的使用方法
  8. AWS redshift-hdb pg(Greenplum), 内置函数、数据类型、字符集
  9. 渗透测试工程师面试题
  10. 键盘RK987说明书
  11. Exception | This means that said other beans do not use the final version of the bean. This is often
  12. 下载Nvidia显卡以前的驱动
  13. 2018上交软科计算机科学排名,2018年上海软科世界一流学科排名出炉!
  14. IDEA创建maven工程(傻瓜式步骤)
  15. 服务器带宽什么意思?影响带宽的因素有哪些?
  16. python项目实战(二):选课系统(采用面向对象思想开发)
  17. 腾讯云IoT边缘服务,助力6000亩沙漠变良田
  18. 动力环境监控系统包括哪些设备
  19. 京东数科区块链开源底层JD Chain版本升级,获工信部功能测试证书
  20. TCPMP的ARM编译器问题

热门文章

  1. 指纹识别综述(10): 深度学习方法
  2. 关于Cisco路由器配置DHCP全面详解
  3. 【echarts记录 -- 3d 饼状图实现】
  4. Ubuntu1804安装nginx
  5. Hadoop势微,云原生上位——传统大数据平台的云原生化改造
  6. 打印Diamond钻石图案
  7. android qq分身,手机qq怎么分身
  8. 为什么需要 Kubernetes 准入控制器
  9. seo网站优化人员的工作是什么样的?
  10. [c++学习笔记19]:stack容器