Python Cookbook --第一章:数据结构和算法(2)

 Python Cookbook --第一章:数据结构和算法(1)

问题11:序列中出现次数最多的元素?

  • Collections.Counter类就是专门为这类问题而设计的,他甚至有一个有用的most_common()方法直接给出答案。

>>> c = Counter("asdwqdsadsdqwdsafqefqdsadqwdasdaww")

>>> c

Counter({'d': 9, 'a': 6, 's': 6, 'w': 5, 'q': 5, 'f': 2, 'e': 1})

>>> c.most_common(4)

[('d', 9), ('a', 6), ('s', 6), ('w', 5)]

  • 关于Counter的其他应用

Counter({'d': 9, 'a': 6, 's': 6, 'w': 5, 'q': 5, 'f': 2, 'e': 1})

>>> c["z"]=1  //直接将c当成字典使用。

>>> c

Counter({'d': 9, 'a': 6, 's': 6, 'w': 5, 'q': 5, 'f': 2, 'e': 1, 'z': 1})

>>> new = "dasdxxzzsdasdwdawdwadadadsddwdwadw"

>>> c.update(new)  //直接更新c

>>> c

Counter({'d': 22, 'a': 13, 'w': 11, 's': 10, 'q': 5, 'z': 3, 'f': 2, 'x': 2, 'e': 1})

  • 关于Counter的数学运算

>>> a = Counter("adsdaasdsdsdwdadsd")

>>> b = Counter("fdfadsadadqwdsadsasadadw")

>>> a

Counter({'d': 8, 's': 5, 'a': 4, 'w': 1})

>>> b

Counter({'d': 8, 'a': 7, 's': 4, 'f': 2, 'w': 2, 'q': 1})

>>> c = a+b

>>> c

Counter({'d': 16, 'a': 11, 's': 9, 'w': 3, 'f': 2, 'q': 1})

>>> d = a-b

>>> d         //若数值为负数,直接丢弃。

Counter({'s': 1})

 

问题12:通过某个(某几个)关键字排序一个字典列表。

  • 通过使用operator模块的itemgetter函数,可以非常容易地排序这样地数据结构。

rows = [

... {"fname":"Brian","lname":"Jones","uid":1003},

... {"fname":"David","lname":"Beazlie","uid":1002},

... {"fname":"Jods","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': 'Beazlie', 'uid': 1002},

{'fname': 'Jods', 'lname': 'Cleese', 'uid': 1001}]

  • Itemgetter()函数也支持多个keys,代码如下:

>>> rows_by_flname = sorted(rows,key=itemgetter("fname","lname"))

>>> rows_by_flname

[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004},

 {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},

 {'fname': 'David', 'lname': 'Beazlie', 'uid': 1002},

{'fname': 'Jods', 'lname': 'Cleese', 'uid': 1001}]

 

问题13:排序不支持原生比较的对象。

  • 解释一下原生比较(个人理解):就是直接扔到sorted()里没有办法排序的,只能通过指定其对象中的一个属性来排序。如下面例子,不使用key = lambda u: u.user_id,则会运行报错。错误如下:  

 File "14.1.py", line 12, in sort_notcompare

    print(sorted(users))

TypeError: unorderable types: User() < User()

  • 像数字一类的可以直接扔进sorted()函数中,直接排序。
  • 内置的sorted()函数有一个关键字参数key,可以传入一个可迭代对象,这个对象对每个传入的对象返回一个值,这个值会被sorted用来排序这些对象。例如:

from operator import attrgetter

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(4), User(43)]

    print(users)

   # print(sorted(users, key = lambda u: u.user_id))

    print(sorted(users, key = attrgetter("user_id"))) #这句可以代替上面语句

sort_notcompare()

 

运行结果:

[User(23), User(4), User(43)]

[User(4), User(23), User(43)]

 

 

问题14:通过么个字段将记录分组

有一个字典或者实例的序列,然后根据某个特定的字段比如data来分组迭代访问。

  • 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'},

]

 

  • 假设现在想按data分组后的数据块上进行迭代。为了这样做,首先需要按照指定的字段排序,然后调用itertools.groupby()函数:

>>> rows.sort(key = itemgetter("date"))  #这里若不排序,会得不到预期的结果。

>>> rows

[{'address': '5412 N CLARK', 'date': '07/01/2012'},

{'address': '4801 N BROADWAY', 'date': '07/01/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'},

{'address': '2122 N CLARK', 'date': '07/03/2012'},

{'address': '5148 N CLARK', 'date': '07/04/2012'},

{'address': '1039 W GRANVILLE', 'date': '07/04/2012'}

]

>>> 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()时,会出现下面的结果:

07/01/2012

  {'address': '5412 N CLARK', 'date': '07/01/2012'}

07/04/2012

  {'address': '5148 N CLARK', 'date': '07/04/2012'}

07/02/2012

  {'address': '5800 E 58TH', 'date': '07/02/2012'}

07/03/2012

  {'address': '2122 N CLARK', 'date': '07/03/2012'}

07/02/2012

  {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}

  {'address': '1060 W ADDISON', 'date': '07/02/2012'}

07/01/2012

  {'address': '4801 N BROADWAY', 'date': '07/01/2012'}

07/04/2012

       {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}

 

问题15:过滤序列元素

有一个数据序列,利用一些规则从中提取需要的值或者是缩短序列。

  • 最简单的过滤序列元素的方法就是使用列表推导式

>>> mylist = [1,4,-5,20,-7,2,3,-1]

>>>

>>> [n for n in mylist if n>0]

[1, 4, 20, 2, 3]

  • 使用列表推导的一个潜在缺陷就是:如果输入很大数据,那么就会产生一个非常大的结果集,占用大量内存。故采用生成器表达式迭代产生过滤的元素。

>>> gen = (n for n in mylist if n>0)  #使用生成器

>>> for i in gen:

...     print(i)

...

1

4

20

2

3

  • 如果过滤规则比较复杂,不能使用列表推导式和生成器表达式,则需要使用内建的filter()函数
  • Filter()函数创建的是一个迭代器对象,因此想要得到一个列表的话,就需要用list()去转换

>>> values = [1,2,3,4,5,6,7,8,9]

>>> def is_even(num):

...     if num%2==0:

...         return True

...     else:

...         return False

...

>>> res = filter(is_even,values)

>>> res

<filter object at 0x000001B3A0819C88>

>>> list(res)

[2, 4, 6, 8]

  • 另外一个值得关注的过滤工具就是itertools.compress(),它以一个iterable对象和一个相对应的Boolean选择器序列作为输入参数。然后输出iterable对象中对应选择器为True的元素。

>>> counts = [0,3,10,4,1,7,6,1]

>>> mores = [n>5 for n in counts]

>>> mores

[False, False, True, False, False, True, True, False]

>>> Data = [1,2,3,4,5,6,7,8]

>>> from itertools import compress

>>> compress(Data,mores)  # 产生的是一个迭代器对象

<itertools.compress object at 0x000001B3A0819C18>

>>> list(compress(Data,mores))

[3, 6, 7]

 

问题16:从字典中提取子集

构造一个字典,它是另一个字典的子集。

  • 最简单的方式是使用字典推导。

>>> prices = {

... 'ACME': 45.23,

... 'AAPL': 612.78,

... 'IBM': 205.55,

... 'HPQ': 37.20,

... 'FB': 10.75

... }

>>> p1 = {key:value for key,value in prices.items() if value>200}

>>> p1

{'AAPL': 612.78, 'IBM': 205.55}

 

>>> tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}

>>> p2 = {key:value for key,value in prices.items() if key in tech_names}

>>> p2

{'AAPL': 612.78, 'IBM': 205.55, 'HPQ': 37.2}

  • 通过创建一个元组序列然后把它传给dict()函数也可以实现。(速度比上面慢)

>>> p1 = dict((key,value) for key,value in prices.items() if value>200)

>>> p1

{'AAPL': 612.78, 'IBM': 205.55}

 

问题17:映射名称到序列元素

有一段通过下标访问列表或者元组元素的代码,但是这样会使得代码难以阅读,但是通过名称来访问元素会较好。

  • Collections.nametuple()函数 (命名元组)通过使用一个普通的元组对象可以解决这个问题。这个函数实际上是一个返回Python中标准元组类型子类的一个工厂方法。需要传递一个类型名和所定制的字段给它,然后他就会返回一个类。示例如下:

>>> from collections import namedtuple

>>> s = namedtuple("ss",["name","age"])  #返回一个方法

>>> data = s("zhoulala","18")  #让字段和数据绑定

>>> data

ss(name='zhoulala', age='18')

>>> data.name

'zhoulala'

>>> data.age

'18'

 

 

问题18:转换并同时计算数据

若需要在数据序列上执行聚集函数(比如sum(),min(),max()),但是首先需要转换或者过滤数据。

  • 一个优雅的方式去结合计算与转换就是使用一个生成器表达式参数,示例如下:

>>> s = sum((x*x for x in nums))  # 使用生成器表达式,其()可以省略

>>> s

55

>>> s = sum([x*x for x in nums])  # 使用列表推导式,但是缺陷在于他首先会创建一个列表,当数据量较大时,这种仅仅使用一次的列表会非常浪费内存。

>>> s

55

 

问题19:合并多个字典或者映射

有多个字典或者映射,若想将它们从逻辑上合并为一个单一的映射后执行某些操作,比如查找值或者检查某些键是否存在。

  • 假设必须在两个字典中执行查找操作 (比如先从 a 中找,如果找不到再在 b中找)。一个非常简单的解决方案就是使用 collections 模块中的 ChainMap 类。比如:

>>> from collections import ChainMap

>>> a = {"x":1,"z":3}

>>> b = {"y":2,"z":4}

>>> c["x"]

1

>>> c["z"]  # 返回的是第一个字典a中所对应的值

3

  • ChainMap 接受多个字典并将它们在逻辑上变为一个字典。然后,这些字典并不是真的合并在一起了, ChainMap 类只是在内部创建了一个容纳这些字典的列表并重新定义了一些常见的字典操作来遍历这个列表。对于字典的更新或者删除操作总是影响的是第一个字典。

>>> c

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

>>> del c["y"]  # 想删除第二个字典中的“y”,则会报错。

KeyError: 'y'

 

>>> del c["z"]  # 删除“z”,’则第一个字典中的z被删除。

>>> c

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于微信小程序的家政服务预约系统采用PHP语言和微信小程序技术,数据库采用Mysql,运行软件为微信开发者工具。本系统实现了管理员和客户、员工三个角色的功能。管理员的功能为客户管理、员工管理、家政服务管理、服务预约管理、员工风采管理、客户需求管理、接单管理等。客户的功能为查看家政服务进行预约和发布自己的需求以及管理预约信息和接单信息等。员工可以查看预约信息和进行接单。本系统实现了网上预约家政服务的流程化管理,可以帮助工作人员的管理工作和帮助客户查询家政服务的相关信息,改变了客户找家政服务的方式,提高了预约家政服务的效率。 本系统是针对网上预约家政服务开发的工作管理系统,包括到所有的工作内容。可以使网上预约家政服务的工作合理化和流程化。本系统包括手机端设计和电脑端设计,有界面和数据库。本系统的使用角色分为管理员和客户、员工三个身份。管理员可以管理系统里的所有信息。员工可以发布服务信息和查询客户的需求进行接单。客户可以发布需求和预约家政服务以及管理预约信息、接单信息。 本功能可以实现家政服务信息的查询和删除,管理员添加家政服务信息功能填写正确的信息就可以实现家政服务信息的添加,点击家政服务信息管理功能可以看到基于微信小程序的家政服务预约系统里所有家政服务的信息,在添加家政服务信息的界面里需要填写标题信息,当信息填写不正确就会造成家政服务信息添加失败。员工风采信息可以使客户更好的了解员工。员工风采信息管理的流程为,管理员点击员工风采信息管理功能,查看员工风采信息,点击员工风采信息添加功能,输入员工风采信息然后点击提交按钮就可以完成员工风采信息的添加。客户需求信息关系着客户的家政服务预约,管理员可以查询和修改客户需求信息,还可以查看客户需求的添加时间。接单信息属于本系统里的核心数据,管理员可以对接单的信息进行查询。本功能设计的目的可以使家政服务进行及时的安排。管理员可以查询员工信息,可以进行修改删除。 客户可以查看自己的预约和修改自己的资料并发布需求以及管理接单信息等。 在首页里可以看到管理员添加和管理的信息,客户可以在首页里进行家政服务的预约和公司介绍信息的了解。 员工可以查询客户需求进行接单以及管理家政服务信息和留言信息、收藏信息等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值