Python数据结构和算法

Posted HT . WANG

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python数据结构和算法相关的知识,希望对你有一定的参考价值。

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 deque


def search(lines, pattern, history=5):
    previous_lines = deque(maxlen=history)
    for line in lines:
        if pattern in line:
            yield line, previous_lines
        previous_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 = 0
        
    def push(self, item, priority):
        heapq.heappush(self.__queue, (-priority, self.__index, item))
        # 第一个参数:添加进的目标序列
        # 第二个参数:将一个元组作为整体添加进序列,目的是为了方便比较
        # 在priority相等的情况下,比较_index
        # priority为负数使得添加时按照优先级从大到小排序,因为堆排序的序列的第一个元素永远是最小的
        self.__index += 1
        
    def 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 defaultdict

d = 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 OrderedDict

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

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 item
            seen.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 item
            seen.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_id

    def __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 True
    except 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.0
    for rec in records:
        total += rec[1] * rec[2]#存储结构为一个很大的元组列表,通过下标去操作其中的元素, 当你在结构中添加了新的列的时候你的代码可能就会出错了
    return total



from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def compute_cost(records):
    total = 0.0
    for rec in records:
        s = Stock(*rec)
        total += s.shares * s.price
    return 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数据结构和算法的主要内容,如果未能解决你的问题,请参考以下文章

Python生成器&迭代器

python中都有哪些简单的算法?

Python实现八大排序算法

Python数据结构与算法(2.7)——跳表

python插入排序算法总结

Python数据结构与算法(2.2)——顺序表