在Python中对字典列表的列表进行排序

6

我有一个对象,它是一个字典列表的列表:

myObject =[[{ "play": 5.00, "id": 1, "uid": "abc" },  \
            { "play": 1.00, "id": 2, "uid": "def" }], \
           [{ "play": 6.00, "id": 3, "uid": "ghi" },  \
            { "play": 7.00, "id": 4, "uid": "jkl" }], \
           [{ "play": 3.00, "id": 5, "uid": "mno" },  \
            { "play": 1.00, "id": 6, "uid": "pqr" }]]

我希望按照嵌套列表中每个字典的play值的总和对列表进行排序。这样,该对象将按以下方式排序:

myObject =[[{ "play": 6.00, "id": 3, "uid": "ghi" },  \
            { "play": 7.00, "id": 4, "uid": "jkl" }], \
           [{ "play": 5.00, "id": 1, "uid": "abc" },  \
            { "play": 1.00, "id": 2, "uid": "def" }], \
           [{ "play": 3.00, "id": 5, "uid": "mno" },  \
            { "play": 1.00, "id": 6, "uid": "pqr" }]]

如果只是一个字典列表,那么以下代码可以实现排序: sorted(myObject, key=sum(map(itemgetter(play))), reverse=True) 但我无法想出在不循环列表、计算总和并进行排序的情况下如何实现。目前我的做法就是这样,但由于我的列表中有数亿个列表,所以我正在尝试通过去除循环来提高代码的效率。

3
请注意:这里不需要使用行尾的“\”来换行。由于每一行以逗号结尾,且列表仍然“开放”,Python会自动将下一行作为继续该列表。 - poke
1个回答

5

您的想法已经很好了,可以在排序时使用自定义键函数并在summapitemgetter中使用play键:

key=sum(map(itemgetter(play)))

不过,您有一个问题: key 参数需要一个接收您正在排序的列表中的项目的函数。但是,summap 都没有返回函数,因此您不能将它作为键函数使用。相反,您可以创建一个 lambda 函数,为每个项目执行此组合。

另外两个问题是,play 应该是字符串 'play',而 map 应该带有子列表作为参数。因此,您的键函数看起来像这样:

key=lambda x: sum(map(itemgetter('play'), x))

这实际上相当于以下生成器推导式,可能更易读:
```python (x for x in iterable if x is not None) ```
key=lambda x: sum(y['play'] for y in x)

使用sorted应该可以工作,但你应该考虑直接使用list.sort对列表进行排序:
>>> myObject = [[{ "play": 5.00, "id": 1, "uid": "abc" },
                 { "play": 1.00, "id": 2, "uid": "def" }],
                [{ "play": 6.00, "id": 3, "uid": "ghi" },
                 { "play": 7.00, "id": 4, "uid": "jkl" }],
                [{ "play": 3.00, "id": 5, "uid": "mno" },
                 { "play": 1.00, "id": 6, "uid": "pqr" }]]

>>> myObject.sort(key=lambda x: sum(y['play'] for y in x), reverse=True)

>>> for x in myObject:
        print(x)

[{'play': 6.0, 'uid': 'ghi', 'id': 3}, {'play': 7.0, 'uid': 'jkl', 'id': 4}]
[{'play': 5.0, 'uid': 'abc', 'id': 1}, {'play': 1.0, 'uid': 'def', 'id': 2}]
[{'play': 3.0, 'uid': 'mno', 'id': 5}, {'play': 1.0, 'uid': 'pqr', 'id': 6}]

顺便说一下,myObject 不是一个好的列表名称。


就问题的效率或复杂度而言,你确实无法避免最终必须循环遍历每个子列表。要确定这些值的总和,必须查看这些值,因此显然你无法避免这种情况。

但是,应确保每个总和仅计算一次,以避免多次查看子列表中的项。幸运的是,使用list.sort 的默认排序正好保证了这一点:

与列表中每个项目对应的键只计算一次,然后用于整个排序过程。

因此,您将拥有非常高效的解决方案来解决此排序问题。


应该不是 reverse=True 才能得到最高的吗? - Paul Rooney
@PaulRooney 噢,是的,我错过了问题中的那个细节(尽管它与排序问题无关)。谢谢! - poke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接