• Python中列表(list)、字典(dict)排序的程序


    Python3 中的排序,在 Sorting HOW TO 中已经讲得很清楚了。来个实际的例子,对下面的这个 list 依据创建时间排序:

    pages = [
    {'title': '十年学会程序设计', 'time': '2012-02-14', 'name': '21-days'},
    {'title': 'ANE Toolkit', 'time': '2012-06-07', 'name': 'anetoolkit'},
    {'title': 'cocos2d-x-filters', 'time': '2015-05-06', 'name': 'cocos2d-x-filters'},
    {'title': '我的Firefox插件', 'time': '2006-05-23', 'name': 'firefox-addons'},
    {'title': 'Flash&Flex大全', 'time': '2005-11-02', 'name': 'flashassistant'},
    {'title': '提问的智慧', 'time': '2005-10-08', 'name': 'howtoask'},
    {'title': 'Linux软件', 'time': '2009-04-30', 'name': 'linux-software'},
    {'title': 'Platform ANEs', 'time': '2013-08-22', 'name': 'platform-anes'},
    {'title': '阅读', 'time': '2015-03-03', 'name': 'read'},
    {'title': 'Sprite Sheet Editor', 'time': '2011-08-18', 'name': 'sprite_sheet_editor'},
    {'title': 'SpriteSheetPacker', 'time': '2011-04-19', 'name': 'spritesheetpacker'},
    {'title': 'WordPress大全', 'time': '2006-03-07', 'name': 'wordpressfavorite'},
    {'title': 'WPCMD', 'time': '2015-06-12', 'name': 'wpcmd'}
    ]
    首先,排序需要一个可以比较的对象,我使用键名为 index 中的对象:

    from datetime import date

    for item in pages:
    t = item['time'].split('-')
    item['index'] = date(int(t[0]), int(t[1]), int(t[2]))
    date 的实例是可比较的(它实现了 __lt__ 那一套方法), date(2012,2,14) < data(2005, 11, 2) == False 。

    然后,对 pages 调用 sort 方法:

    pages.sort(key=lambda item : item['index'])
    在这里,我需要为 key 传递一个函数,这个函数能返回需要比较的值。

    当然,也可以使用 operator 提供的 itemgetter 方法来获取这个待比较的值。

    from operator import itemgetter
    names.sort(key=itemgetter('index'))
    除了 itemgetter 之外, operator 模块还提供了 attrgetter 和 methodcaller 。

    张贺 对上面提到的 Sorting Mini-HOW TO 做了一些必要的中文评注,该文和 Sorting HOW TO 基本相同。

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

    通过使用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}
    >>>


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

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

    讨论
    选择使用lambda函数或者是 attrgetter() 可能取决于个人喜好。 但是,attrgetter() 函数通常会运行的快点,并且还能同时允许多个字段进行比较。 这个跟 operator.itemgetter() 函数作用于字典类型很类似(参考1.13小节)。 例如,如果User实例还有一个first_name和last_name属性,那么可以向下面这样排序:

    by_name = sorted(users, key=attrgetter('last_name', 'first_name'))
    同样需要注意的是,这一小节用到的技术同样适用于像 min() 和 max() 之类的函数。比如:

    >>> min(users, key=attrgetter('user_id')
    User(3)
    >>> max(users, key=attrgetter('user_id')
    User(99)
    >>>

  • 相关阅读:
    派遣函数
    英文论文(1)
    状态机和时序图的“前世姻缘”
    线程安全性:原子性,安全性,加锁机制
    多线程程序中操作的原子性
    win10下安装Centos7总笔记!
    分支限界法---旅行售货员问题
    PHP+ajax聊天室源码!支持长轮循跟定时请求两种
    elasticsearch配置优化
    hbase region与内存的关系
  • 原文地址:https://www.cnblogs.com/zqifa/p/python-sort.html
Copyright © 2020-2023  润新知