python3学习笔记3---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/
2018-03-01数据结构和算法(3)
1.11 命名切片
假定你有一段代码要从一个记录字符串中几个固定位置提取出特定的数据字段(比如文件或类似格式):
- ###### 0123456789012345678901234567890123456789012345678901234567890'
- record = '....................100 .......513.25 ..........'
- cost = int(record[20:23]) * float(record[31:37])
与其那样写,为什么不想这样命名切片呢:
- SHARES = slice(20, 23)
- PRICE = slice(31, 37)
- cost = int(record[SHARES]) * float(record[PRICE])
内置的 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]
如果你有一个切片对象a,你可以分别调用它的 a.start
, a.stop
, a.step
属性来获取更多的信息。比如:
- >>> a = slice(5, 50, 2)
- >>> a.start
- 5
- >>> a.stop
- 50
- >>> a.step
- 2
- >>>
另外,你还能通过调用切片的 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
- >>>
1.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
对象可以接受任意的由可哈希(hashable
)元素构成的序列对象。 在底层实现上,一个 Counter
对象就是一个字典,将元素映射到它出现的次数上。比如:
- >>> word_counts['not']
- 1
- >>> word_counts['eyes']
- 8
- >>>
如果你想手动增加计数,可以简单的用加法:
- >>> morewords = ['why','are','you','not','looking','in','my','eyes']
- >>> 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,
- "you're": 1, "don't": 1, 'under': 1, 'not': 1})
- >>> b
- Counter({'eyes': 1, 'looking': 1, 'are': 1, 'in': 1, 'not': 1, 'you': 1,
- 'my': 1, 'why': 1})
- >>> # Combine counts
- >>> c = a + b
- >>> c
- Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'not': 2,
- 'around': 2, "you're": 1, "don't": 1, 'in': 1, 'why': 1,
- 'looking': 1, 'are': 1, 'under': 1, 'you': 1})
- >>> # Subtract counts
- >>> d = a - b
- >>> d
- Counter({'eyes': 7, 'the': 5, 'look': 4, 'into': 3, 'my': 2, 'around': 2,
- "you're": 1, "don't": 1, 'under': 1})
- >>>
毫无疑问, Counter
对象在几乎所有需要制表或者计数数据的场合是非常有用的工具。 在解决这类问题的时候你应该优先选择它,而不是手动的利用字典去实现。
1.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'}]
itemgetter()
函数也支持多个 keys,比如下面的代码:
- 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'}]
在上面例子中, 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_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
这种方案也不错。但是,使用 itemgetter()
方式会运行的稍微快点。因此,如果你对性能要求比较高的话就使用 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}
- >>>
1.14排序不支持原生比较对象
内置的 sorted()
函数有一个关键字参数 key
,可以传入一个 callable
对象给它, 这个 callable
对象对每个传入的对象返回一个值,这个值会被 sorted
用来排序这些对象。 比如,如果你在应用程序里面有一个 User
实例序列,并且你希望通过他们的 user_id
属性进行排序, 你可以提供一个以 User
实例作为输入并输出对应 user_id
值的 callable
对象。比如:
- class User:
- def __init__(self, user_id):
- self.user_id = user_id
- def __repr__(self):
- return 'User({})'.format(self.user_id)
- def sort_notcompare():
- users = [User(23), User(3), User(99)]
- print(users)
- print(sorted(users, key=lambda u: u.user_id))
- #另外一种方式是使用 operator.attrgetter() 来代替 lambda 函数:
- >>> from operator import attrgetter
- >>> sorted(users, key=attrgetter('user_id'))
- [User(3), User(23), User(99)]
- >>>
同样需要注意的是,这一小节用到的技术同样适用于像 min()
和 max()
之类的函数。比如:
- >>> min(users, key=attrgetter('user_id'))
- User(3)
- >>> max(users, key=attrgetter('user_id'))
- User(99)
- >>>
1.15通过某个字段将记录分组
- 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'},
- ]
现在假设你想在按 date 分组后的数据块上进行迭代。为了这样做,你首先需要按照指定的字段(这里就是 date
)排序, 然后调用 itertools.groupby()
函数:
- 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
- {'date': '07/01/2012', 'address': '5412 N CLARK'}
- {'date': '07/01/2012', 'address': '4801 N BROADWAY'}
- 07/02/2012
- {'date': '07/02/2012', 'address': '5800 E 58TH'}
- {'date': '07/02/2012', 'address': '5645 N RAVENSWOOD'}
- {'date': '07/02/2012', 'address': '1060 W ADDISON'}
- 07/03/2012
- {'date': '07/03/2012', 'address': '2122 N CLARK'}
- 07/04/2012
- {'date': '07/04/2012', 'address': '5148 N CLARK'}
- {'date': '07/04/2012', 'address': '1039 W GRANVILLE'}
groupby()
函数扫描整个序列并且查找连续相同值(或者根据指定 key 函数返回值相同)的元素序列。 在每次迭代的时候,它会返回一个值和一个迭代器对象, 这个迭代器对象可以生成元素值全部等于上面那个值的组中所有对象。
一个非常重要的准备步骤是要根据指定的字段将数据排序。 因为 groupby()
仅仅检查连续的元素,如果事先并没有排序完成的话,分组函数将得不到想要的结果。
如果你仅仅只是想根据 date
字段将数据分组到一个大的数据结构中去,并且允许随机访问, 那么你最好使用 defaultdict()
来构建一个多值字典,关于多值字典已经在 1.6 小节有过详细的介绍。比如:
- from collections import defaultdict
- rows_by_date = defaultdict(list)
- for row in rows:
- rows_by_date[row['date']].append(row)
这样的话你可以很轻松的就能对每个指定日期访问对应的记录:
- >>> for r in rows_by_date['07/01/2012']:
- ... print(r)
- ...
- {'date': '07/01/2012', 'address': '5412 N CLARK'}
- {'date': '07/01/2012', 'address': '4801 N BROADWAY'}
- >>>
在上面这个例子中,我们没有必要先将记录排序。因此,如果对内存占用不是很关心, 这种方式会比先排序然后再通过 groupby()
函数迭代的方式运行得快一些。
python3学习笔记3---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/的更多相关文章
- python3学习笔记1---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/
2018-02-28数据结构和算法(1) 1.1解压序列赋值给多个变量: 任何的序列(或者是可迭代对象)可以通过一个简单的赋值语句解压并赋值给多个变量. 唯一的前提就是变量的数量必须跟序列元素的数量是 ...
- python3学习笔记4---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/
2018-03-01数据结构与算法(4) 1.16过滤序列元素 最简单的过滤序列元素的方法就是使用列表推导.比如: >>> mylist = [1, 4, -5, 10, -7, 2 ...
- python3学习笔记2---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/2
2018-03-01数据结构和算法(2) 1.6字典中的键映射多个值 一个字典就是一个键对应一个单值的映射.如果你想要一个键映射多个值,那么你就需要将这多个值放到另外的容器中, 比如列表或者集合里面. ...
- python3学习笔记(6)_iteration
#python3 学习笔记17/07/10 # !/usr/bin/env python3 # -*- coding:utf-8 -*- #类似 其他语言的for循环,但是比for抽象程度更高 # f ...
- Python3学习笔记(urllib模块的使用)转http://www.cnblogs.com/Lands-ljk/p/5447127.html
Python3学习笔记(urllib模块的使用) 1.基本方法 urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, ...
- Python3学习笔记 - 准备环境
前言 最近乘着项目不忙想赶一波时髦学习一下Python3.由于正好学习了Docker,并深深迷上了Docker,所以必须趁热打铁的用它来创建我们的Python3的开发测试环境.Python3的中文教程 ...
- python3学习笔记(7)_listComprehensions-列表生成式
#python3 学习笔记17/07/11 # !/usr/bin/env python3 # -*- conding:utf-8 -*- #通过列表生成式可以生成格式各样的list,这种list 一 ...
- python3学习笔记(5)_slice
#python3 学习笔记17/07/10 # !/usr/bin/env python3 # -*- coding:utf-8 -*- #切片slice 大大简化 对于指定索引的操作 fruits ...
- python3.4学习笔记(一) 基本语法 python3不向下兼容,有些语法跟python2.x不一样
python3.4学习笔记(一) 基本语法 python3不向下兼容,有些语法跟python2.x不一样,IDLE shell编辑器,快捷键:ALT+p,上一个历史输入内容,ALT+n 下一个历史输入 ...
随机推荐
- Android Studio 使用 Gradle 打包 Jar
Android Studio 打 Jar 包一直是一个麻烦的事,按照网上现有的教程,打包一个混淆的 jar 需要完成下列步骤: 1.将 plugin 修改为 library 后 build 出 aar ...
- HTML5 预加载
原文地址: HTML5 Link Prefetching 原文日期: 2010年07月07日 翻译日期: 2013年08月13日 浏览器厂商和开发者之间共同努力的一个方向就是让网站更快.现在已有很多广 ...
- noSQL数据库相关软件介绍(大数据存储时候,必须使用)
目前图数据库软件七种较为流行:Neo4J, Infinite Graph, DEX,InfoGrid, HyperGraphDB, Trinity, AllegroGraph(http://tech. ...
- 【Android 多媒体开发】 MediaPlayer 网络视频播放器
作者 : 万境绝尘 (octopus_truth@163.com) 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/3889514 ...
- 网站开发进阶(二十九)HTML特殊转义字符
HTML特殊转义字符 参考文献 http://tool.oschina.net/commons?type=2 美文美图
- JVM 类的生命周期、类加载器
类的加载.连接与初始化 • 1. 加载:查找并加载类的二进制数据 • 2. 连接 – 2.1 验证:确保被加载的类的正确性 ...
- CTBS问题百科
1.浏览CTBS网站时,Service Unavailable或应用程序池自动停止的现象 解决方法: 点击"开始"-"控制面板"-"管理工具" ...
- Notepad++ 使用探索
一.更换主题,视觉享受 1,http://wiki.macromates.com/Themes/UserSubmittedThemes,从网站上下载自己喜欢的主题,解压 2,复制Black Pearl ...
- JavaScript进阶(五)js中取小数整数部分函数
js中取小数整数部分函数 丢弃小数部分,保留整数部分 js:parseInt(7/2) 向上取整,有小数就整数部分加1 js: Math.ceil(7/2) 四舍五入 js: Math.round(7 ...
- cocos2d-x action执行完毕的回调
cocos2d-x action执行完毕的回调 MySprite::createOne() { .... // MUST add to sheet firstly spriteShee ...