[英]Sort a list of dict by key. If key is missing, assume a consecutive numbering
I want so sort a list of dictionaries by the key "pos".我想按“pos”键对字典列表进行排序。 However, if "pos" is missing in the dict, I want to keep the order of the item(s) and assume that "pos" is the item's 1-based index in the list.
但是,如果字典中缺少“pos”,我想保持项目的顺序并假设“pos”是项目在列表中基于 1 的索引。
This is working fine, as long as all list items are different:这工作正常,只要所有列表项不同:
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: Output:
[{'id': '1'}, {'id': '2'}, {'id': '3'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '4'}, {'id': 'ZZZ'}, {'id': 'AAA'}]
But it fails if I have multiple of the same items, because then list.index
will return the first occurence, rather than the "assumed position".但如果我有多个相同的项目,它会失败,因为
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)
Actual output:实际 output:
[{'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': 'AAA'}]
Expected output:预期 output:
[{'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '1'}, {'id': '1'}, {'id': 'AAA'}]
How can the sorting be changed to return the expected output?如何更改排序以返回预期的 output?
Note: the item IDs are not guaranteed to be in any order, that means 1,2,3,4,AAA,ABC,XYZ
have been chosen arbitrarily.注意:项目 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 Output
[{'id': '1'}, {'id': '2'}, {'id': '3'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '4'}, {'id': 'ZZZ'}, {'id': 'AAA'}]
For the duplicates example:对于重复示例:
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 Output
[{'id': '1'}, {'id': '1'}, {'id': '1'}, {'id': 'XYZ', 'pos': 3.1}, {'id': 'ABC', 'pos': 3.2}, {'id': '1'}, {'id': '1'}, {'id': 'AAA'}]
A perhaps cleaner alternative is to use itertools.count :一个可能更清洁的替代方法是使用itertools.count :
from itertools import count
counter = count(1)
result = sorted(L, key=lambda x: x.get("pos", next(counter)))
print(result)
We can do something like this:我们可以这样做:
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.