按键对字典列表进行排序。如果键不存在,则假定为连续编号。

4
我想按“pos”键对字典列表进行排序。但是,如果字典中没有“pos”,我希望保留项目的顺序,并假设“pos”是该项目在列表中的基于1的索引。
只要所有列表项都不同,这个方法就可以正常工作:
L = [
    {   "id": "1" }, # assume pos: 1
    {   "id": "2" }, # assume pos: 2
    {   "id": "3" }, # assume pos: 3
    {   "id": "4" }, # assume pos: 4
    {   "id": "ZZZ" }, # assume pos: 5
    {   "id": "AAA" }, # assume pos: 6
    {   "id": "ABC", "pos": 3.2 },
    {   "id": "XYZ", "pos": 3.1 },
]

s = sorted(L,key=lambda i:i.get("pos",L.index(i)+1))
print(s)

输出:

[{'id': '1'}, {'id': '2'}, {'id': '3'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '4'}, {'id': 'ZZZ'}, {'id': 'AAA'}]

但是如果我有多个相同的项目,这段代码就会失败,因为list.index将返回第一个出现的位置,而不是“假定的位置”。
L = [
    {   "id": "1" }, # assume pos: 1
    {   "id": "1" }, # assume pos: 2
    {   "id": "1" }, # assume pos: 3
    {   "id": "1" }, # assume pos: 4
    {   "id": "1" }, # assume pos: 5
    {   "id": "AAA" }, # assume pos: 6
    {   "id": "ABC", "pos": 3.2 },
    {   "id": "XYZ", "pos": 3.1 },
]

s = sorted(L,key=lambda i:i.get("pos",L.index(i)+1))
print(s)

实际输出:

[{'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': 'AAA'}]

期望输出:

[{'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '1'}, {'id': '1'}, {'id': 'AAA'}]

如何更改排序以返回期望的输出?
注意:项目 ID 没有保证以任何顺序排列,这意味着 1、2、3、4、AAA、ABC、XYZ 是任意选择的。
2个回答

6

使用枚举功能:

L = [
    {"id": "1"},  # assume pos: 1
    {"id": "2"},  # assume pos: 2
    {"id": "3"},  # assume pos: 3
    {"id": "4"},  # assume pos: 4
    {"id": "ZZZ"},  # assume pos: 5
    {"id": "AAA"},  # assume pos: 6
    {"id": "ABC", "pos": 3.2},
    {"id": "XYZ", "pos": 3.1},
]

result = [e for _, e in sorted(enumerate(L, 1), key=lambda x: x[1].get("pos", x[0]))]

print(result)

输出

[{'id': '1'}, {'id': '2'}, {'id': '3'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '4'}, {'id': 'ZZZ'}, {'id': 'AAA'}]

对于重复项示例:
L = [
    {"id": "1"},  # assume pos: 1
    {"id": "1"},  # assume pos: 2
    {"id": "1"},  # assume pos: 3
    {"id": "1"},  # assume pos: 4
    {"id": "1"},  # assume pos: 5
    {"id": "AAA"},  # assume pos: 6
    {"id": "ABC", "pos": 3.2},
    {"id": "XYZ", "pos": 3.1},
]

result = [e for _, e in sorted(enumerate(L, 1), key=lambda x: x[1].get("pos", x[0]))]

print(result)

输出

[{'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '1'}, {'id': '1'}, {'id': 'AAA'}]

也许更简洁的替代方法是使用 itertools.count:
from itertools import count

counter = count(1)

result = sorted(L, key=lambda x: x.get("pos", next(counter)))
print(result)

0
我们可以这样做:
d = [
    {"id": "1"}, # assume pos: 1
    {"id": "1"}, # assume pos: 2
    {"id": "1"}, # assume pos: 3
    {"id": "1"}, # assume pos: 4
    {"id": "1"}, # assume pos: 5
    {"id": "AAA"}, # assume pos: 6
    {"id": "ABC", "pos": 3.2},
    {"id": "XYZ", "pos": 3.1},
]


def my_compare(x):
    if 'pos' in x[1]:
        return x[1]['pos']
    return x[0] + 1

sorted_d = [x[1] for x in sorted(enumerate(d), key=my_compare)]

expected_output = [
    {'id': '1'}, 
    {'id': '1'}, 
    {'id': '1'}, 
    {'id': 'XYZ','pos': 3.1}, 
    {'id': 'ABC','pos': 3.2}, 
    {'id': '1'}, 
    {'id': '1'}, 
    {'id': 'AAA'},
]
assert sorted_d == expected_output


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