Python数据结构和算法

将序列分解为单独变量

我们有一个N个元素的元组或者序列,想要分解为N个单独的变量

解决方案:任何序列或者可迭代的对象(包括字符串,文件,迭代器以及生成器)都要通过一个简单的赋值操作来分解为单独的变量,要求是变量的总数和结构要与序列吻合。

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> p = (4,5)
>>> x,y = p
>>> x
4
>>> y
5

从任意长度的可迭代对象中分解元素

上面我们说过可以通过赋值操作来分解单独的变量,但是要求变量总数与结构要与序列吻合,如果需要从某个可迭代对象中分解出N个元素,但是可迭代的对象长度超过N的时候就会导致如下异常:

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> p = (1,2,3)
>>> x,y = p
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

解决方案:利用*表达式,可以处理分解位置或者任意长度的可迭代对象,或者在迭代一个变长的元组序列,以及结合某些特定的字符串处理操作,比如拆分操作。

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> *headdata,current=[10,3,2,6,8,5] #*修饰的变量位于列表第一个位置,轻松分别头部和尾部
>>> headdata
[10, 3, 2, 6, 8]
>>> current
5
>>> 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']
>>> line='nobody:*:-2:-3:Unpriviledged User:/var/empty:/usr/bin/false'
>>> uname,*fields,homedir,sh=line.split(':') #*修饰的变量位于中间位置,且与字符串处理操作相结合
>>> uname
'nobody'
>>> homedir
'/var/empty'
>>> sh
'/usr/bin/false'
>>> fields
['*', '-2', '-3', 'Unpriviledged User']

保存最后N个元素

deque(maxlen=N)创建一个固定长度的队列,当有新的记录加入而队列已经满时,会自动移除老的记录(队列更加优雅和快速),如果不指定队列的大小,就会得到一个无界限的队列。

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from collections import deque
>>> 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)

找到最大或最小的N个元素

可以用最大(最小)堆。假设现在要找N个最大的元素,则首先把前N个元素入堆,并形成最小堆(堆顶元素为最小元素),下面每次有新元素来都和堆顶元素比较,如果小于等于堆顶元素则抛弃,否则删除堆顶元素并将新元素入堆,并维持堆序。如此下去直到遍历所有元素。heapq模块中的nlargest()和nsmallest()两个函数正好可以实现我们的需求。

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import heapq
>>> nums = [1,2,3,4,5,6,7,8,9]
>>> print(heapq.nlargest(3,nums))
[9, 8, 7]
>>> print(heapq.nsmallest(3,nums))
[1, 2, 3]

如果同集合中元素总数目相比,N很小,那么下面的函数可以提供更好的性能,首先会在底层将数据转换成列表,且元素会以堆的顺序排列。

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> nums = [1,5,3,-6,33,44,67]
>>> import heapq
>>> heap = list(nums)
>>> heapq.heapify(heap)
>>> heap
[-6, 1, 3, 5, 33, 44, 67]

如果N与集合本身的大小差不多,通常更快的方法是先对集合排序,再切片,这两个函数实际实现会跟使用它们的方法不同,会做一些优化,比如N大小与集合相近的时候,会采用排序的方法。

在字典中将键映射到多个值上

通常可以使用集合或者列表来实现:

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

为了能更方便的创建字典,可以使用defaultdict:

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d['a'].append(1)
>>> d['a'].append(2)
>>> d['b'].append(4)
>>> print(d)
defaultdict(<class 'list'>, {'a': [1, 2], 'b': [4]})

创建一键多值的字典很容易,但是如果试着对第一个值初始化的时候,就会变得杂乱:

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

使用defaultdict后代码会清晰很多:

d = defaultdict(list)
for key, value in pairs:
    d[key].append(value)

参考来源:

  1. 《Python Cookbook》
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容