簡體   English   中英

按鍵排序字典列表。 如果 key 缺失,假設一個連續的編號

[英]Sort a list of dict by key. If key is missing, assume a consecutive numbering

我想按“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)

Output:

[{'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)

實際 output:

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

預期 output:

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

如何更改排序以返回預期的 output?

注意:項目 ID 不保證按任何順序排列,即1,2,3,4,AAA,ABC,XYZ已被任意選擇。

使用枚舉

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)

Output

[{'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)

Output

[{'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)

我們可以這樣做:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM