IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 【Python 每日一技】针对元素为字典的列表按照共同的键进行排序 -> 正文阅读

[Python知识库]【Python 每日一技】针对元素为字典的列表按照共同的键进行排序

1 问题

你有一个列表,列表中的元素均为字典,你希望通过字典中的一个或多个键对列表进行排序。

2. 解决方案

针对上述需求,使用 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}
...]

如果希望按照列表中每个字典的特定键进行排序,则利用 operator 模块的 itemgetter 类如下:

  • 按照键 'fname' 进行排序:
>>> 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': 'Beazley', 'uid': 1002}, 
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}
]
  • 按照键 'uid' 进行排序:
>>> rows_by_uid = sorted(rows, key=itemgetter('uid'))
>>> rows_by_uid
[
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, 
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, 
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, 
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]

实际上,类 itemgetter 还接受多个对象初始化参数。例如:

  • 先按照键 'lname' 在按照键 'fname' 进行排序:
>>> rows_by_lname_fname = sorted(rows, key=itemgetter('lname', 'fname'))
>>> rows_by_lname_fname
[
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, 
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, 
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, 
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}
]

3. 讨论

在上述案例中,元素为字典的列表 rows 被传递至函数 sorted() ,该函数还接受一个键值对参数 key ,该参数需要是一个可调用对象,该对象本身接受接受一个参数(在这里该参数是列表 rows 的每一个元素,即字典)作为输入,调用该对象会返回一个值用作排序,而 itemgetter 类创建的就恰恰是 sorted 函数通过 key 接受的可调用对象。例如:

>>> getter = itemgetter('lname', 'fname')
>>> getter(rows[0])
('Jones', 'Brian')

>>> getter = itemgetter('lname', 'fname', 'uid')
>>> getter(rows[1])
('Beazley', 'David', 1002)

在上述案例中,使用 operator.itemgetter() 类创建可调用对象时,初始化方法接受的参数会被用作查找的索引,后续在调用该对象时会返回根据索引查找得到的值。

实际上,该对象的初始化方法接受的参数除了可以是字典的键名以外,还可以是列表的索引,更进一步地,如果一个对象中实现了 __getitem__() 方法,这些参数还可以是实现 __getitem__() 方法时使用的任何类型对象。

如上所述,如果你在创建 itemgetter 实例时为初始化方法传入了多个后续用作查找的索引,那么在调用该对象后也将返回一个同样大小的元组,元组的每个元素都是使用对应索引查找出的值。

在实际中,类 itemgetter 的功能通常会被 lambda 表达式所代替。例如:

>>> rows_by_fname = sorted(rows, key=lambda row: row['fname'])
>>> rows_by_fname
[
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, 
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, 
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, 
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}
]

>>> rows_by_lname_fname = sorted(rows, key=lambda row: (row['lname'], row['fname']))
>>> rows_by_lname_fname
[
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, 
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, 
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, 
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}
]

上述两种方法的都可以实现需求,然而使用 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}

4. 拓展

下面是 itemgetter 类的源码,不长,花几分钟就能看懂。使用该类创建的对象会有两个实例属性:

  • self._items :用于以元组的形式保存创建对象时初始化方法接受的参数;
  • self._call :一个函数的引用,该函数在 itemgetter 的初始化方法中定义,而且该函数返回的是根据索引 item 查找对象 obj 得到的元素。

在调用 itemgetter 的实例时,实例的 __call__() 方法会被调用,该方法会返回 self._call(obj) 的结果。

class itemgetter:
    """
    Return a callable object that fetches the given item(s) from its operand.
    After f = itemgetter(2), the call f(r) returns r[2].
    After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])
    """
    __slots__ = ('_items', '_call')

    def __init__(self, item, *items):
        if not items:
            self._items = (item,)
            def func(obj):
                return obj[item]
            self._call = func
        else:
            self._items = items = (item,) + items
            def func(obj):
                return tuple(obj[i] for i in items)
            self._call = func

    def __call__(self, obj):
        return self._call(obj)

    def __repr__(self):
        return '%s.%s(%s)' % (self.__class__.__module__,
                              self.__class__.__name__,
                              ', '.join(map(repr, self._items)))

    def __reduce__(self):
        return self.__class__, self._items
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 20:45:38  更:2022-03-21 20:46:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 19:37:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码