鱼C论坛

 找回密码
 立即注册
楼主: lightninng

[技术交流] [记录贴]每天的问题和解决方法_正确学习方法

[复制链接]
发表于 2015-5-22 08:26:45 | 显示全部楼层
佩服你强大的自学能力
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-22 09:42:25 | 显示全部楼层
wwsw0105 发表于 2015-5-22 08:26
佩服你强大的自学能力

谢谢,其实很天做做checkio,或者坚持看某本书,然后把所学所想记下来,不知不觉就能学到东西,贵在坚持,欢迎多来交流~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-5-22 21:16:09 | 显示全部楼层

专门开一贴热烈庆祝升级


心情舒畅~
可以加好友啦
可以发短消息啦
关键可以发悬赏啦
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-22 21:33:31 | 显示全部楼层
smallwan 发表于 2015-5-22 21:16
专门开一贴热烈庆祝升级

我能说当初我和你是一样的心情么~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-26 13:20:28 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-26 13:22 编辑

虽然要答辩了,但是ppt好难做,饭前看了checkio ,吃饭的时候想了想,然后回来把东西跑通,除了吃饭一共花了1个小时,然后继续ppt了~~!
我开始喂鸽子群之中的一只。一分钟后又飞来了两只鸽子,再过一分钟又飞来了三只,以此类推(例如:1+2+3 +4+......)。食品的一份可以让鸽子吃一分钟,但如果没有足够的食物,让那些先到的鸟先吃。 鸽子是非常饥饿的动物,他们不会停止进食。如果我有 N份的鸟饲料,有多少鸽子至少吃到一份小麦?
visual.jpg
输入:小麦的份数 (int)。
输出:已经喂食过的鸽子的数目 (int)。
范例:
checkio(1) == 1checkio(2) == 1checkio(5) == 3checkio(10) == 6   
如何使用: 此任务说明了我们可以怎样去模拟不同的情况。当然,该模型具有有限近似的性质,但通常我们并不需要一个完美的模型。
前提:0 < N < 105.
  1. def checkio(number):
  2.     s = lambda n: n* (n+ 1) * (n+ 2) / 6
  3.     i = 1
  4.     while s(i) <= number:
  5.         i += 1
  6.     return i * (i - 1) / 2 if number - s(i - 1) < 2 else number - s(i - 1) + i * (i - 1) / 2
复制代码
用了点数学知识:
第n天所有的鸽子一共吃1 + 2 + ... + n 份, 即n * (n + 1) / 2 = n ^2 / 2 + n / 2  # 等差数列求和
n天会消耗粮食((1^2 + 2^2 + ... + n^2) + (1 + 2 + ... + n)) / 2
(1^2 + 2^2 + ... + n^2) = n * (n + 1) * (2 * n + 1) / 6  # 自然数平方和公式
n天共消耗粮食(n * (n + 1) * (2 * n + 1) / 6 + n * (n + 1) /2) / 2 = n* (n+ 1) * (n+ 2) / 6
然后找到到第几天粮食不够,再求最后结果
想的很复杂,其实看看first的解法
  1. """Determine the number of (greedy) pigeons who will be fed."""
  2. import itertools
  3. &#8203;
  4. def checkio_first(food):
  5.     """Given a quantity of food, return the number of pigeons who will eat."""
  6.     pigeons = 0
  7.     for t in itertools.count(1):
  8.         if pigeons + t > food:
  9.             # The food will be consumed this time step.
  10.             # All pigeons around last time were fed, and there is enough food
  11.             # this time step to feed 'food' pigeons, so return the max of each.
  12.             return max(pigeons, food)
  13.         # Increase pigeons, decrease food.
  14.         pigeons += t
  15.         food -= pigeons
复制代码
感觉不用过多解释 ,里面的注释写的非常清楚
学到的东西有itertools模块中的count函数,可以生成指定步长的无限迭代器,我是用while实现的~~!


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-5-28 20:52:06 | 显示全部楼层
棒棒的,加油!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-29 01:56:19 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-29 22:59 编辑

今天早上终于答辩完了,晚上玩了两个checkio,放一个出来:
Minand Max

在这个任务中,你应该自己写出PY3中实现的内建函数 minmax。 一些内建函数在这里是不能用的:importevalexecglobals。 别忘了,你需要在你的代码中实现两个函数。
max(iterable, *[, key]) 或者 min(iterable, *[, key])
max(arg1, arg2, *args[, key])
或者 min(arg1, arg2, *args[, key])
返回迭代中的最大(最小)项中或者返回根据所提供参数的最大(最小)值 。
如果有一个参数时,它应该是一个迭代器。返回在迭代器的最大(最小)的项。如果提供两个或更多的参数,返回参数中的最大(最小)的项。
可选的唯一关键字是一个用于从每个列表元素提取一个用于比较的参数的函数。(例如,key=str.lower.lower)
如果有多个值同是最大(最小)的,函数返回所遇到的第一个最大值。

-- Python 文档 (内建函数)

输入:一个参数作为一个迭代器或两个以上的参数。    一个函数作为可选关键字参数。
输出:"max" 函数输出最大的项 "min" 函数输出最小的项。
范例:
max(3, 2) == 3min(3, 2) == 2max([1, 2, 0, 3, 4]) == 4min("hello") == "e"max(2.2, 5.6, 5.9, key=int) == 5.6min([[1,2], [3, 4], [9, 0]], key=lambda x: x[1]) == [9, 0
如何使用: 此任务将帮助你了解一些内置的功能是如何在更精确的水平上工作的。
前提: 所有的测试用例都是正确的并且函数不会引发异常。
  1. def min(*args, **kwargs):
  2.     key = kwargs.get("key", lambda x: x)
  3.     iterative_object = args if len(args) > 1 else list(args[0])
  4.     flag_index, flag_data = 0, iterative_object[0]
  5.     for index, each in enumerate(iterative_object):
  6.         if key(each) < key(flag_data):
  7.             flag_data = key(each)
  8.             flag_index = index
  9.     return iterative_object[flag_index]


  10. def max(*args, **kwargs):
  11.     key = kwargs.get("key", lambda x: x)
  12.     iterative_object = args if len(args) > 1 else list(args[0])
  13.     flag_index, flag_data = 0, iterative_object[0]
  14.     for index, each in enumerate(iterative_object):
  15.         if key(each) > key(flag_data):
  16.             flag_data = key(each)
  17.             flag_index = index
  18.     return iterative_object[flag_index]
复制代码
写的第一版,发现除了if语句中的比较以外都是重复的,学编程的都知道"don't repeat yourself"吧~~,于是改进一下
  1. def func_select(func):
  2.     if func.__name__ == "min":
  3.         compare = lambda *min_args: min_args[0] < min_args[1]
  4.     else:
  5.         compare = lambda *max_args: max_args[0] > max_args[1]
  6.     def min_or_max(*args, **kwargs):
  7.         key = kwargs.get("key", lambda x: x)
  8.         iterative_object = args if len(args) > 1 else list(args[0])
  9.         flag_index, flag_data = 0, iterative_object[0]
  10.         for index, each in enumerate(iterative_object):
  11.             if compare(key(each), key(flag_data)):
  12.                 flag_data = key(each)
  13.                 flag_index = index
  14.         return iterative_object[flag_index]
  15.     return min_or_max

  16. @func_select
  17. def min(*args, **kwargs):
  18.     pass

  19. @func_select
  20. def max(*args, **kwargs):
  21.     pass
复制代码
这里用到的python的装饰器,不明白的鱼油请看这个贴子http://www.liaoxuefeng.com/wiki/ ... b18034f0254bf355000用用装饰器的原因是,根据函数名的不同,在函数体内只有if的判断语句不同,所以只要将判断语句抽象成函数,然后根据函数名不同在if语句处调用不不同的函数即可一次完成两个函数,compare函数即为我们构造的比较函数,根据不同的情况(即函数名为"min"和"max"时),将不同的lambda表达式赋于compare,放在if语句处即可。
成功的用了装饰器很高兴~~
看看第一名的函数
  1. def get_first_from_sorted(args, key, reverse):
  2.     if len(args) == 1:
  3.         args = iter(args[0])
  4.     return sorted(args, key=key, reverse=reverse)[0]
  5. &#8203;
  6. &#8203;
  7. def min(*args, key=None):
  8.     return get_first_from_sorted(args, key, False)
  9. &#8203;
  10. &#8203;
  11. def max(*args, key=None):
  12.     return get_first_from_sorted(args, key, True)
复制代码
只能说自叹不如,1.用内置函数sorted完成对它的排序,然后取第一个,这个想法我也有过(可惜把key=key弄丢了~~)
2.自己在用排序时,仅仅取第一个为最小,最后一个为最大,当最大值有多个时,取的是最后面那个不符合题目要求,但是用reserve参数完美解决这个问题,这也说明python内置的sort方法和sorted函数均为稳定的排序方法(即排序结束后,相同大小的两个值的相对顺序不变),这里我想到之前在网上看到的说python内置的排序算法是用快速排序,但是通过数据结构的学习我们知道快速排序是不稳定的排序算法,所以python到底用的是什么方法,还可以继续讨论~
自己在试验中学习和巩固的知识有:
1、字典的get方法,可以用于实现类似于C语言中的switch语句,当某种情况不存在时,设定get的第二个参数为缺省函数
2、认识到了内置函数的强大,python内置的sort方法和sorted函数的排序速度是很快的,而且可以处理迭代器,列表,元组,字符串等各种可迭代结构,这给编码带来很大的方便,所以实际上上面的第一名的解法中对args[0]可以不使用iter函数转化为生成器
3、对装饰器的用法有了更深的理解,虽然这里其实并不需要,看了别人的代码之后发现,其实只要重新写的函数,然后max和min函数都调用这个函数,然后传入不同的参数即可,不过don't repeat yourself还是要好好记得的~~
4、这里展示了reverse(sorted(test), key=func)与sorted(test,key=func,reverse=True)这两种方法的不同于test = [3.1, 5.6, 5.9]来说前者的结果是[5.9, 5.6, 3.1]后者的结果是[5.6, 5.9, 3.1]
5、在给compare函数赋值的过程中遇到一个奇怪的现象,最开始我的方法是这样的
  1.     compare = lambda *min_args: min_args[0] < min_args[1] if func.__name__ == "min" \
  2.         else lambda *max_args: max_args[0] > max_args[1]
复制代码
但是当func.__name__ 不等于"min"时,我得到的compare函数无法正常工作,在idle里试验的结果是这样的
  1. >>> compare(1,2)
  2. <function <lambda>.<locals>.<lambda> at 0x00000000033270D0>
复制代码
借助鱼油的帮助,原因已经找到。我的赋值方式相当于
  1. compare = lambda *min_args: ((min_args[0] < min_args[1]) if func.__name__ == "min" \
  2.         else (lambda *max_args: max_args[0] > max_args[1]))
复制代码
正确的写法有两种
  1. compare = lambda *args: ( args[0] < args[1] if key == "<" else args[0] > args[1] )
  2. compare = ( lambda *args: args[0] < args[1] ) if key == "<" else ( lambda *args: args[0] > args[1] )
复制代码
6、最后函数的默认参数的传入方式可以用字典,其中字典中,参数的名字一定要是字符串类型,如我把自己的代码改一下变成这样
  1. def func_select_2(func):
  2.     def min_or_max(*args, **kwargs):
  3.         key = kwargs.get("key", lambda x: x)
  4.         sort_args = {"min": {"key": key}, "max": {"key": key, "reverse": True}}
  5.         iterative_object = iter(args) if len(args) > 1 else iter(args[0])
  6.         return sorted(iterative_object, **sort_args[func.__name__])[0]
  7.     return min_or_max

  8. @func_select_2
  9. def min_2(*args, **kwargs):
  10.     pass

  11. @func_select_2
  12. def max_2(*args, **kwargs):
  13.     pass
复制代码
2点了,睡觉~~明天继续pyqt5那个贴子最后的俄罗斯方块的钻研,找工作并不顺利,也要劲了,加油!!!!!!!!!!!!!!!!!







想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-2 01:57:43 | 显示全部楼层
[python cookbook]
问题:怎样在一个序列上面保持元素顺序的同时消除重复的值?
解决:如果序列上的值都是hashable类型,那么可以很简单的利用集合或者生成器来解决这个问题
PS:什么叫harshable,我的理解是可以用索引直接获得的容器,如列表和元组,而字典和集合都无法通过索引获得(它们内部的顺序和输入顺序无关)
  1. def dedupe(items):
  2.     seen = set()
  3.         for item in items:
  4.             if item not in seen:
  5.                 yield item
  6.                 seen.add(item)
复制代码
不懂什么叫生成器(代码中的yield语句是生成器函数的要点),请看这里http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00138681965108490cb4c13182e472f8d87830f13be6e88000
  1. >>> a = [1, 5, 2, 1, 9, 1, 5, 10]
  2. >>> list(dedupe(a))
  3. [1, 5, 2, 9, 10]
  4. >>>
复制代码
PS:当序列上的值不为hashable时,为什么不能用上面的函数呢,因为集合中的元素必须是harshable的元素,试一试
  1. >>> a = set([{1: 'a', 2: 'b'}, {3: 'c', 4: 'd'}])
  2. Traceback (most recent call last):
  3.   File "<pyshell#14>", line 1, in <module>
  4.     a = set([{1: 'a', 2: 'b'}, {3: 'c', 4: 'd'}])
  5. TypeError: unhashable type: 'dict'
  6. >>>
复制代码
那么当元素为字典时,怎么做呢
  1. def dedupe(items, key=None):
  2.     seen = set()
  3.     for item in items:
  4.         val = item if key is None else key(item)
  5.         if val not in seen:
  6.             yield item
  7.             seen.add(val)
复制代码
这里的key参数指定了一个函数,将序列元素转换成hashable类型。下面是它的用法示例:
  1. >>> a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
  2. >>> list(dedupe(a, key=lambda d: (d['x'],d['y'])))
  3. [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
  4. >>> list(dedupe(a, key=lambda d: d['x']))
  5. [{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
  6. >>>
复制代码

可以看到lambda函数其实就是将字典中每个键对应的值按顺序组成元组,dedupe函数的这个key参数是否似曾相识?
对了,python内置方法中的max,min,sorted,方法都有key参数,再深想一想,其实就是映射的过程 ,用一个key函数将原数据映射成新的数据,然后比较大小,或者排序,或者进行其它操作,其实都是map思想的一个延伸,举一反三~~

如果我们不要求元素相对顺序保持不变,那么直接将序列转化为集合是一个好的方法
最后,这个方法可以用到的地方很多,举个例子,比较你在读取文件时,想去掉重复的行可以这么做:
  1. with open(somefile,'r') as f:
  2. for line in dedupe(f):
  3.     ...
复制代码




想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-4 00:02:34 | 显示全部楼层
昨天晚上花了很久看之前在论坛上看到的一篇关于好习惯养成的贴子,里面涉及了内容很多,主要的收获是哪些习惯是有好处的,怎么样养成习惯这两个问题:
于是,做了一个决定, 花一百天时间培养几个习惯,其实都是很小的事情 ,但是实际操作起来对自己可能会有一些难度,今天没什么时间了,明天开一个贴子,记录我的完成情况:
一般没时间,或者没心情,我选择看一节python cookbook:
问题:你的程序已经出现一大堆已无法直视的硬编码切片下标,然后你想清理下代码。换句话说,你想给你的切片方式起个名字,然后复用它。
解决:python内置的slice类型可以帮助你

比如下面的例子
  1. ###### 0123456789012345678901234567890123456789012345678901234567890'
  2. record = '....................100 .......513.25 ..........'
  3. cost = int(record[20:23]) * float(record[31:37])
复制代码
你可以为你的切片方式20:30和31:27分别起个名字,下次用的时候直接输入名字即可

  1. SHARES = slice(20, 23)
  2. PRICE = slice(31, 37)
  3. cost = int(record[SHARES]) * float(record[PRICE])
复制代码
PS:记住定义一个slice变量时,传入参数是用逗号隔开的而不是冒号,这个问题我出过很多次

一个切片对象,包含三个属性值start,stop,step,顾名思义,分别的起始位置,终止位置和步长,你可以用属性名直接取到它们
  1. >>> test = slice(0, 50, 2)
  2. >>> test.start
  3. 0
  4. >>> test.stop
  5. 50
  6. >>> test.step
  7. 2
复制代码
同切片取值时的规则相同,当你不定义step属性时,它的默认值是1

另外slice类的变量有一个indices方法,这个方法返回一个三元组(start,stop,step),这里的start和stop都会被限定到你输入的范围内
  1. >>> test.indices(len(s))
  2. (0, 10, 2)
  3. >>> for i in range(*test.indices(len(s))):
  4.         print(s[i])

  5.        
  6. H
  7. l
  8. o
  9. o
  10. l
  11. >>>
复制代码
PS:这个indices方法仅仅只是简单的限定一下范围,所以有时候它并不好用

  1. >>> test = slice(10, 50, 2)
  2. >>> test.indices(5)
  3. (5, 5, 2)
复制代码







想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-4 23:47:13 | 显示全部楼层
本帖最后由 lightninng 于 2015-6-4 23:51 编辑

今天是100天计划第一天,并不太顺利,python cookbook继续
问题:怎样找出一个序列中出现次数最多的元素呢?
解决:collections模块中的Counter类为你提供了统计出现次数的功能,它可以对生成器使用,更专业的说法,它可以接受一切hashable的序列对象。

比如下面的例子
  1. words = [
  2.     'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
  3.     'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
  4.     'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
  5.     'my', 'eyes', "you're", 'under'
  6. ]
  7. from collections import Counter
  8. word_counts = Counter(words)
  9. # 出现频率最高的3个单词
  10. top_three = word_counts.most_common(3)
  11. print(top_three)
  12. # Outputs [('eyes', 8), ('the', 5), ('look', 4)]
复制代码
PS:首先,你要注意是Counter而不是counter,它是一个类,这个类的一个非常有用的方法most_commen,它返回出现频次最高的k个元素和他们的出现次数组成的元组,k是由你指定的。

Counter对象的表现就像一个字典,你可以直接将元素做为键,取到它出现的次数
  1. >>> word_counts['not']
  2. 1
  3. >>> word_counts['eyes']
  4. 8
  5. >>>
复制代码
当然,你也可以直接修改它们,和字典里修改值是一样的方法(比如你想更新新的数据统计值),当然如果你想加一组新的序列和原有的统计值合并,你可以用update方法

  1. >>> morewords = ['why','are','you','not','looking','in','my','eyes']
  2. >>> word_counts.update(morewords)
复制代码
最后,作者给我们介绍了Counter类的一个有取的特性,它们可以直接进行数学运算

  1. >>> a = Counter(words)
  2. >>> b = Counter(morewords)
  3. >>> a
  4. Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2,
  5. "you're": 1, "don't": 1, 'under': 1, 'not': 1})
  6. >>> b
  7. Counter({'eyes': 1, 'looking': 1, 'are': 1, 'in': 1, 'not': 1, 'you': 1,
  8. 'my': 1, 'why': 1})
  9. >>> # Combine counts
  10. >>> c = a + b
  11. >>> c
  12. Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'not': 2,
  13. 'around': 2, "you're": 1, "don't": 1, 'in': 1, 'why': 1,
  14. 'looking': 1, 'are': 1, 'under': 1, 'you': 1})
  15. >>> # Subtract counts
  16. >>> d = a - b
  17. >>> d
  18. Counter({'eyes': 7, 'the': 5, 'look': 4, 'into': 3, 'my': 2, 'around': 2,
  19. "you're": 1, "don't": 1, 'under': 1})
  20. >>>
复制代码
PS:对于c = a + b 和d = a - b 两种操作,它实际是实现了键的集合运算和值的加减运算两种运算,对于两个对象都有的键,直接对它们对应的值进行加减运算;对于一方有,另一方没有的键,加法运算会将所有在a和b中出现的键均放c中,减法则会在a中仅对b里也出现的键值进行减法操作

另外,dict方法是没有+法和-法操作,其实学了甲鱼小哥,魔法方法的朋友,可以手动的实现一下Counter类的这几个特性


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-6-5 08:50:31 | 显示全部楼层
非常棒的学习记录贴,mark,太长了一下子看不完
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-5 10:27:49 | 显示全部楼层
ft3312591 发表于 2015-6-5 08:50
非常棒的学习记录贴,mark,太长了一下子看不完

谢谢,欢迎来交流~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-7 19:31:10 | 显示全部楼层
本帖最后由 lightninng 于 2015-6-14 21:32 编辑

最近几天不停的看贴,做一些没有生产力的事情 ,希望这种情况能早点结束,不管怎么样,自己的三个贴子还是希望每天至少 能更新一个,这是对自己的最低要求~~继续
[python cookbook]
问题:通过某个关键字排序一个字典列表
解决:使用operator模块的itemgetter函数

例子:比如数据库中检索出几条用户信息(字典类型),放在一个列表中
  1. rows = [
  2.     {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
  3.     {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
  4.     {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
  5.     {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
  6. ]
复制代码
想根据其中的某些字段对这些信息进行排序
  1. from operator import itemgetter
  2. rows_by_fname = sorted(rows, key=itemgetter('fname'))
  3. rows_by_uid = sorted(rows, key=itemgetter('uid'))
  4. print(rows_by_fname)
  5. print(rows_by_uid)
复制代码
输出是这样的
  1. [{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'},
  2. {'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'},
  3. {'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},
  4. {'fname': 'John', 'uid': 1001, 'lname': 'Cleese'}]
  5. [{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'},
  6. {'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},
  7. {'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'},
  8. {'fname': 'Big', 'uid': 1004, 'lname': 'Jones'}]
复制代码
PS:看到sored函数中的key方法,有些鱼油可能会想到这个itemgetter做的事情自己也能实现,比如自己定义一个函数
  1. def get_item(my_dict):
  2.         return my_dict['fname']
复制代码
更好一些的,比如使用lambda表达式,把上面的sorted语句 变成这样
  1. rows_by_fname = sorted(rows, key=lambda d: d['fname'])
复制代码
那么这个itemgetter到底有什么特别之处,先来看看它的一种用法
  1. rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
  2. print(rows_by_lfname)
复制代码
输出是这样的
  1. [{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},
  2. {'fname': 'John', 'uid': 1001, 'lname': 'Cleese'},
  3. {'fname': 'Big', 'uid': 1004, 'lname': 'Jones'},
  4. {'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'}]
复制代码
这里itemgetter是把lname和fname两个键所对应的值组成元组传给sorted进行对字典的排序,即itemgetter支持多个key的输入
有些鱼油会说,我用lambda也能实现
  1. rows_by_fname = sorted(rows, key=lambda d: (d['lname'], d['fname']))
复制代码
确实如此,从效果上来说两者差不多,但是用itemgetter的话,处理的速度会稍微快一点(PS:我没有探究内部的原因,但我理解python的内置库大多数是用C实现的底层,所以效率会更好)最后,别忘了max函数和min函数也有key参数~~

_______________________________________________________________________________________________________________________
PS:最后补充一点由于好奇心做的一些测试,关于lambda表达试和itemgetter的效率的对比
  1. from time import clock
  2. clock()
  3. rows = [
  4.     {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
  5.     {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
  6.     {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
  7.     {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
  8. ]
  9. from operator import itemgetter
  10. clock_1 = clock()
  11. for i in range(100000000):
  12.     rows_by_fname = sorted(rows, key=itemgetter('fname'))
  13. clock_2 = clock()
  14. for i in range(100000000):
  15.     rows_by_fname = sorted(rows, key=lambda r: r['fname'])
  16. clock_3 = clock()
  17. print(clock_2-clock_1)
  18. print(clock_3-clock_2)
复制代码

输出是这样的
  1. >>> ================================ RESTART ================================
  2. >>>
  3. 131.9878048702259
  4. 152.43856409098458
复制代码



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-10 22:05:36 | 显示全部楼层
[python cookbook]
问题:排序不支持原生比较的对象解决:使用sorted函数的key参数
PS:实际的问题是根据对象的某个属性来对它们排序,很熟悉有木有,上节讲的是根据字典的某一个或几个键的值来排序它们,解决方法是使用sorted函数的key参数,函数为operator模块中的itemgetter函数或者使用lambda表达式。

这个问题同样有lambda表达式和operator模块中的attrgetter函数两种方法
先来看lambda表达式
  1. class User:
  2.     def __init__(self, user_id):
  3.         self.user_id = user_id

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


  6. def sort_notcompare():
  7.     users = [User(23), User(3), User(99)]
  8.     print(users)
  9.     print(sorted(users, key=lambda u: u.user_id))
复制代码
然后是attrgetter函数
  1. >>> from operator import attrgetter
  2. >>> sorted(users, key=attrgetter('user_id'))
  3. [User(3), User(23), User(99)]
  4. >>>
复制代码
PS:上面的代码中不知道__repr__方法的可以把甲鱼小哥视频魔法方法那几节看一下

这里attrgetter和上节的itemgetter一样,有两个好处:
1、可以取多个属性,它会按属性名的顺序,将属性值组成元组返回用于排序
2、它会比lambda表达式的运行效率稍微高一点

最后同样的别忘了max和min函数也有key参数




想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-6-11 09:16:23 | 显示全部楼层
棒棒哒!加油!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-6-11 10:50:46 | 显示全部楼层
看不懂大神们留下的东东,我还是要到处蹭鱼币吧,为了下载课后题,如果谁能发我一份 学习Python007以后 的课后题的话,那真是感激不尽了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-11 21:56:11 | 显示全部楼层
gagafishc 发表于 2015-6-11 10:50
看不懂大神们留下的东东,我还是要到处蹭鱼币吧,为了下载课后题,如果谁能发我一份 学习Python007以后 的 ...

加油吧~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-12 21:32:49 | 显示全部楼层
[python cookbook]
问题:通过某个字段将记录分组,实际问题是你有一个字典或者实例的序列,然后你想根据某个特定的字段比如date来分组迭代访问
解决:使用itertools模块中的groupby方法

例子, 对于下面代码中的row列表想按照"date"的值进行分组迭代
  1. rows = [
  2.     {'address': '5412 N CLARK', 'date': '07/01/2012'},
  3.     {'address': '5148 N CLARK', 'date': '07/04/2012'},
  4.     {'address': '5800 E 58TH', 'date': '07/02/2012'},
  5.     {'address': '2122 N CLARK', 'date': '07/03/2012'},
  6.     {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
  7.     {'address': '1060 W ADDISON', 'date': '07/02/2012'},
  8.     {'address': '4801 N BROADWAY', 'date': '07/01/2012'},
  9.     {'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
  10. ]
复制代码

可以这样做
  1. from operator import itemgetter
  2. from itertools import groupby

  3. # Sort by the desired field first
  4. rows.sort(key=itemgetter('date'))
  5. # Iterate in groups
  6. for date, items in groupby(rows, key=itemgetter('date')):
  7.     print(date)
  8.     for i in items:
  9.         print(' ', i)
复制代码

这段代码的输出是这样的
  1. 07/01/2012
  2.   {'date': '07/01/2012', 'address': '5412 N CLARK'}
  3.   {'date': '07/01/2012', 'address': '4801 N BROADWAY'}
  4. 07/02/2012
  5.   {'date': '07/02/2012', 'address': '5800 E 58TH'}
  6.   {'date': '07/02/2012', 'address': '5645 N RAVENSWOOD'}
  7.   {'date': '07/02/2012', 'address': '1060 W ADDISON'}
  8. 07/03/2012
  9.   {'date': '07/03/2012', 'address': '2122 N CLARK'}
  10. 07/04/2012
  11.   {'date': '07/04/2012', 'address': '5148 N CLARK'}
  12.   {'date': '07/04/2012', 'address': '1039 W GRANVILLE'}
复制代码

PS:有些鱼油可能不明白为什么要先排序,我们看看如果不进行排序(也就是将rows.sort这句注释掉), 输出是怎样的
  1. 07/01/2012
  2.   {'address': '5412 N CLARK', 'date': '07/01/2012'}
  3. 07/04/2012
  4.   {'address': '5148 N CLARK', 'date': '07/04/2012'}
  5. 07/02/2012
  6.   {'address': '5800 E 58TH', 'date': '07/02/2012'}
  7. 07/03/2012
  8.   {'address': '2122 N CLARK', 'date': '07/03/2012'}
  9. 07/02/2012
  10.   {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}
  11.   {'address': '1060 W ADDISON', 'date': '07/02/2012'}
  12. 07/01/2012
  13.   {'address': '4801 N BROADWAY', 'date': '07/01/2012'}
  14. 07/04/2012
  15.   {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}
复制代码

显然,只有在迭代顺序上相邻且'date'的值相同时才会被分为一组(如唯超过一个字典的一组时间都为07/02/2012)同时也可以看到上面的字典中也有'date'值为07/02/2012的,但是由于迭代顺序分开了没有被分在一组

同时我们可以看到很多的函数都具有key这个参数,这些函数有个共同的特征就是涉及到元素之间的比较,key参数的意义是将元素代入key参数所指代的函数,以不同元素的函数返回值做为他们之前的比较结果,这样就多了很多灵活性,上上节学到的itemgetter再次被用到,当然别忘了还有上节学的attrgetter
另外 ,有key参数的函数现在学到的有,max,min,sorted(包括一些类型的sort方法),groupby~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-6-12 22:06:10 | 显示全部楼层
楼主学习的东西太高端了,只能膜拜了~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-12 22:49:01 | 显示全部楼层
昨、夜星辰 发表于 2015-6-12 22:06
楼主学习的东西太高端了,只能膜拜了~

其实都是论坛或者checkio里面的一些小游戏 ,由简入繁,你也可以试试,由其是checkio这个,挺有趣的,我也没学多久python~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 03:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表