您的位置:首页 > 理论基础 > 数据结构算法

Python3 cookbook学习笔记-数据结构与算法4

2017-03-18 11:31 92 查看

命名切片

问题:

你的程序中已经出现一大堆无法直视的硬编码切片下标,然后你想清理一下代码。

解决方案:

假定你有一段代码要从一个记录字符串中几个固定位置 取出特定的数据字段:

>>> record = '....................100 .......513.25 ..........'
>>> cost = int(record[20:23]) * float(record[31:37])
>>> cost
51325.0


与其那样写,为什么不想这样命名切片呢:

>>> SHARES = slice(20,23)
>>> PRICE = slice(31,37)
>>> cost = int(record[SHARES]) * float(record[PRICE])
>>> cost
51325.0


第二种版本更加清晰可读了。

内置的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]


如果你有一个切片对象s,你可以分别调用它的 s.start, s.stop, s.step 属性来获取更 多的信息:

>>> s = slice(5, 50, 2)
>>> s.start
5
>>> s.stop
50
>>> s.step
2
>>>


你还能通过调用切片的 indices(size)将它映射到一个确定大小的序列上, 这歌方法返回一个三元组(start, stop, step),所有值都会被合适的缩小以满足边界限制,从而使用的时候避免出现IndexError异常:

>>> s = 'HelloWorld'
>>> a.indices(len(s))
(2, 4, 1)
>>> a.indices(len(s))
(2, 4, 1)
>>> a.indices(len(s))
(2, 4, 1)
>>> for i in range(*a.indices(len(s))):
...     print(s[i])
...
l
l


个人心得:最后一个例子,没看懂。我自己输出的结果和原书中的结果不同,也不明白这样的做的意义何在。

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

问题:

怎样找出一个序列中出现次数最多的元素呢?

解决方案:

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)
>>> word_counts
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2, 'not': 1, "don't": 1, "you're":
1, 'under': 1})
>>>
>>> top_thress = word_counts.most_common(3)
>>> top_thress
[('eyes', 8), ('the', 5), ('look', 4)]


作为输入,Counter对象可以接受任意的hashable序列对象。在底层实现上,一个Counter对象就是一个字典,将元素映射到它出现的次数上。

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


如果你想手动增加计数,可以简单的用加法:

>>> morewords = ['why','are','you','not','looking','in','my','eyes']
>>> word_counts
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2, 'not': 1, "don't": 1, "you're":
1, 'under': 1})
>>> for word in morewords:
...     word_counts[word] += 1
...
>>> word_counts['eyes']
9
>>>


或者你可以用update()方法:

word_counts.update(morewords)


Counter实例一个鲜为人知的特性是它们可以很容易的跟数学运算操作相结合:

>>> a = Counter(words)
>>> b = Counter(morewords)
>>> a
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2, 'not': 1, "don't": 1, "you're":
1, 'under': 1})
>>> b
Counter({'why': 1, 'are': 1, 'you': 1, 'not': 1, 'looking': 1, 'in': 1, 'my': 1, 'eyes': 1})
>>>
>>> c = a + b
>>>
>>> c
Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'not': 2, 'around': 2, "don't": 1, "you're":
1, 'under': 1, 'why': 1, 'are': 1, 'you': 1, 'looking': 1, 'in': 1})
>>>
>>> d = a - b
>>> d
Counter({'eyes': 7, 'the': 5, 'look': 4, 'into': 3, 'my': 2, 'around': 2, "don't": 1, "you're": 1, 'under
': 1})
>>>


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

问题:

你有一个字典列表,你想根据某个或某几个字典字段来排序这个列表。

解决方案:

通过使用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_fname
[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004},
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]
>>>
>>> rows_by_uid = sorted(rows, key = itemgetter('uid'))
>>> rows_by_uid
[{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}]
>>>


itemgetter()函数也支持多个keys:

>>> rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
>>> rows_by_lfname
[{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004},
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}]
>>>


在上面的例子中, rows被传递给接受一个关键字参数的sorted()内置函数,这个参数是callable类型,并且从rows中接受一个单一元素,然后返回被用来排序的值。

itemgetter()函数就是负责创建这个callable对象的。

operator.itemgetter()函数有一个被rows中的记录用来查找值的索引参数。可以是一个字典键名称、一个整型值或者任何一个能够传入一个对象的getitem()方法的值。如果你传入多个索引参数给itemgetter,它生成的callable对象会返回一个包含所有元素值的元组,并且sorted函数会根据这个元组中元素的顺序去排序。当你想要同时在几个字段上面进行排序的时候,这种方法是很有用的。

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

>>> rows_by_fname = sorted(rows, key=lambda r: r['fname'])
>>> rows_by_fname
[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004},
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]
>>> rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
>>> rows_by_lfname
[{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004},
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}]
>>>


这种方案也不错,但是使用itemgetter会运行地更快点。

最后,本节展示的技术也同样适用于min()和max()等函数:

>>> min(rows, key=itemgetter('uid'))
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}
>>> max(rows, key=itemgetter('uid'))
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
>>>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息