python 食谱-day02

1.11 命名切片
record = '...............................100..........523.35'
#解法一、使用硬编码下标值
cost = int(record[31:34]) * float(record[44:50])
print(cost)

#解法二、命名切片
shares = slice(31,34)
price = slice(44,50)

print(int(record[shares])*float(record[price]))

第二种方式更加清晰可读、可维护性也高
 内置的slice()函数创建了一个切片对象,可以被用在任何切片允许使用的地方。

s = slice(3,50,2)
print(s.start)
print(s.stop)
print(s.step)

3
50
2

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

 怎样找出一个序列中出现次数最多的元素呢?
collections.Counter类就是专门为这类问题而设计的,甚至它提供了一个 most_common()方法可以直接给你答案。

words = ['look','into','my','eyes','look','into','my','eyes','haha','hehe','hhuhu']
from collections import Counter
word_counts = Counter(words)
top_three = word_counts.most_common(3)#出现次数最多的3个单词
print(top_three)

[('into', 2), ('look', 2), ('eyes', 2)]

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

如果你想手动增加技术,可以简单的使用加法:

words = ['look','into','my','eyes','look','into','my','eyes','haha','hehe','hhuhu']
from collections import Counter
word_counts = Counter(words)

more_words = ['good','good','good','study']
word_counts.update(more_words)
top_three = word_counts.most_common(3)#出现次数最多的3个单词
print(word_counts)

Counter({'good': 3, 'into': 2, 'eyes': 2, 'my': 2, 'look': 2, 'haha': 1, 'study': 1, 'hehe': 1, 'hhuhu': 1})

Counter实例可以很容易的跟数学运算操作相结合。所以,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'))
print(rows_by_fname)

rows_by_uid = sorted(rows,key=itemgetter('uid'))
print(rows_by_uid)

[{'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}, {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}]
[{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}]

itemgetter()函数也支持多个keys,比如

rows_by_lfname = sorted(rows,key=itemgetter('lname','fname'))
print(rows_by_lfname)

[{'uid': 1002, 'lname': 'Beazley', 'fname': 'David'}, {'uid': 1001, 'lname': 'Cleese', 'fname': 'John'}, {'uid': 1004, 'lname': 'Jones', 'fname': 'Big'}, {'uid': 1003, 'lname': 'Jones', 'fname': 'Brian'}]

这些东西同样使用于min()max()等函数

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

 你想排序类型相同的对象,但是他们不支持原生的比较操作。

class User:
    def __init__(self,user_id):
        self.user_id = user_id

    def __repr__(self):
        return 'User({})'.format(self.user_id)

from  operator import attrgetter
users = [User(12),User(33),User(24),User(35)]
a = sorted(users,key=attrgetter('user_id'))
print(a)

[User(12), User(24), User(33), User(35)]

也可以使用lambda函数,

def sort_notcompare():
    users = [User(12),User(23),User(34),User(45)]
    print(sorted(users,key=lambda u:u.user_id))

sort_notcompare()

使用attrgetter()函数通常会运行的快点,并且还能同事允许多个字段进行比较。同样的min()max()适用于这些东西

1.15 通过某个字段将记录分组

  你有一个字典或者实力的序列,然后你想根据某个特定的字段比如date来分组迭代访问。
itertools.groupby()函数对于这样的数据分组操作非常实用。

rows = [
    {'address':'安徽淮北','date':'07/01/2012'},
    {'address':'安徽蚌埠','date':'07/04/2012'},
    {'address':'安徽淮南','date':'07/02/2012'},
    {'address':'安徽黑肥','date':'07/03/2012'},
    {'address':'安徽芜湖','date':'07/02/2012'},
    {'address':'安徽黄山','date':'07/02/2012'},
    {'address':'安徽六安','date':'07/01/2012'},
    {'address':'安徽宿州','date':'07/04/2012'},
]

from operator import itemgetter
from itertools import groupby
rows.sort(key=itemgetter('date'))
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': '安徽淮北'}
{'date': '07/01/2012', 'address': '安徽六安'}
07/02/2012
{'date': '07/02/2012', 'address': '安徽淮南'}
{'date': '07/02/2012', 'address': '安徽芜湖'}
{'date': '07/02/2012', 'address': '安徽黄山'}
07/03/2012
{'date': '07/03/2012', 'address': '安徽黑肥'}
07/04/2012
{'date': '07/04/2012', 'address': '安徽蚌埠'}
{'date': '07/04/2012', 'address': '安徽宿州'}

1.16过滤序列元素

 你有一个数据序列,想利用一些规则从中提取出需要的值或者是缩短序列
最简单的方法就是实用列表推导。

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

1
4
10
2
3
++++++
-5
-7
-1

 使用列表推导的一个缺陷就是如果输入非常大的时候会产生一个非常大的结果集,占用大量内存。如果你对内存比较敏感,那么你可以使用生成器表达式迭代产生过滤的元素。

pos = (x for x in mylist if x < 0)
print(pos)
for x in pos:
    print(x)

<generator object <genexpr> at 0x101bd0a40>
-5
-7
-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)

['1', '2', '-3', '4', '5']

 还有一个过滤工具是itertools.compress(),它以一个iterable对象和一个相对应的 Boolean选择器序列作为输入参数。然后输出iterable对象中对应选择器为True的元素。当你需要用另一个相关联的序列来过滤某个序列的时候,这个函数是非常有用的。

addresses = [
    '安徽淮北',
    '安徽南京',
    '安徽马鞍山',
    '安徽芜湖',
    '安徽北京',
    '安徽合肥',
    '安徽悉尼',
    '内蒙古伦敦',
]
counts = [8,2,3,4,5,6,7,8];
from itertools import compress

neq8 = [n==8 for n in counts ]

print(list(compress(addresses,neq8)))

  以上代码的作用是,将那些对应count值大于5的地址全部输出。
  这里的关键点在于先创建一个 Boolean序列,提示哪些元素符合条件,然后compress()函数根据这个序列去选择输出对应位置为True的元素。

1.17从字典中提取子集

  你想构建一个字典,它是另一个字典的子集。(过滤字典中符合条件的部分数据)

prices = {
    'ACME':45.23,
    'APPL':612.78,
    'IBM':205.55,
    'HPQ':37.20,
    'FB':10.75
}
p1 = {key:value for key,value in prices.items() if value > 200}
print(p1)

tech_names = {'APPL','FB','MAOTAI','XIAOMI'}
p2 = {key:value for key,value in prices.items() if key in tech_names}
print(p2)
1.18映射名称到序列元素

  通过名称来访问列表或者元组中的元素。
  collections.namedtuple()函数通过使用一个普通的元组对象来帮你解决这个问题。这个函数实际上是一个返回Python中标准元组类型子类的一个工厂方法。你需要传递一个类型名和你需要的字段给它,然后它就会返回一个类,你可以初始化这个类,为你定义的字段传递值等。

from collections import namedtuple
Subscriber = namedtuple('d',['one','two','three'])
sub = Subscriber('1','2','3')
print(sub)
print(sub.one)
print(sub.two)

d(one='1', two='2', three='3')
1
2

注:namedtuple的实例跟元组类型是可交换的,支持所有的普通元组操作,比如索引和解压

print(len(sub))
x,y,h = sub
print(y)

3
2

  命名元组的一个主要用途是将你的代码从下标操作中解脱出来。因此你从数据库调用中返回了一个很大的元素列表,通过下标去操作其中的元素,当你在表中添加了新的列的时候你的代码可能就出错了。但是如果你使用了命名元组,那么就不会有这样的顾虑。

from collections import namedtuple

Stock = namedtuple('Stock',['name','shares','price'])
def compute_cost(records):
    total = 0.0
    for rec in records:
        #s = Stock(*rec)可以省略,后边直接使用rec.shares
        total += s.shares * s.price
    return total
recs = [Stock("红酒",1,2),Stock("红酒",2,2),Stock("红酒",3,2),Stock("红酒",4,2),Stock("红酒",5,2)]
print(compute_cost(recs))

30.0

  命名元组另一个用于就是作为字典的替代,因为字典存储需要更多的内存空间。但是命名元组是不可以改变的.

s = Stock("coffee",2,5)
print(s)
print(s.name)

Stock(name='coffee', shares=2, price=5)
File "/Users/mudy/Documents/Python/Fishc/day01.py", line 475, in <module>
coffee
s.name = "冰红茶"
AttributeError: can't set attribute

如果真的需要改变其属性值,那么可以使用命名元组实例的_replace()方法,它会创建一个全新的命名元组饼将对应的字段用新的值取代,例

s = s._replace(name="冰红茶")
print(s)
1.19转换并同时计算数据

  你需要在数据序列上执行聚集函数(比如sum(),min(),max()),但是首先你需要先转换或者过滤数据.
  计算平方和

nums = [1,2,3,4,5]
s = sum(num * num for num in nums)
print(s)

55

import os
files = os.listdir()
if any(name.endswith('.py') for name in files):
    print('这里有一个python文件')
else:
    print('这里没有python文件')

print(files)
print(type(files))

s = ('ACME',50,123.45)
print(','.join(str(x) for x in s))

这里有一个python文件
['.idea', 'day01.py', 'decorator.py', 'net.py', 'singleton.py', 'test.db', 'tk1.py', 'tk2.py', 'tk_entry.py', 'tk_tag.py']
<class 'list'>
ACME,50,123.45

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)
res = (s['shares'] for s in portfolio)
print(res)
print(min(res))

<generator object <genexpr> at 0x101bd0a40>
20

min_shares = min(portfolio,key=lambda s:s['shares'])
print(min_shares)

{'shares': 20, 'name': 'AOL'}

1.20合并多个字典或映射

  现在有多个字典或者映射,你想将它们从逻辑上合并为一个单一的映射后来执行某些操作,比如查找值或者检查某些键是否存在。
假如你有两个字典a和b:现在你必须在两个字典中之行查找操作。就可以使用collections模块中的ChainMap

a = {'x':1,'z':3}
b = {'y':2,'z':4}
from collections import  ChainMap
c = ChainMap(b,a)
print(c)
print(c['z'])

ChainMap({'y': 2, 'z': 4}, {'x': 1, 'z': 3})
4

注:注意ChainMap()中参数的顺序
  一个ChainMap接受多个字典并将它们在逻辑上变为一个字典。然后,这些字典并不是真的合并在一起了,ChainMap类只是在内部创建了一个容纳这些字典的列表并重新定义了一些常见的字典操作来遍历这个列表。大部分字典操作都是可以正常使用的。

print(len(c))
print(list(c.values()))

3
[4, 2, 1]

  如果出现重复键,那么第一次出现的映射值会被返回。因此。。
对于字典的更新或删除操作总是影响的是列表中的第一个字典。

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

推荐阅读更多精彩内容