python - Python如何根据元组列表中的值对字典列表进行排序
问题描述
unsorted = [{"#":"1", "files": [("test.txt",1),("example.out",1)]},
{"#":"2", "files": [("other.txt",0),("test.txt",3)]},
{"#":"3", "files": [("example.out",0)]},
{"#":"4", "files": [("test.txt",2)]}]
files
: 其中一个list
是tuples
指一个文件及其rev。例如, ("test.txt",1) 是 rev 1 的文件 test.txt。
需要对对象进行排序unsorted
,使其元素按以下顺序排列:
- 按书名排序
- 如果多个元素具有相同的书名,则次要版本在前
以下是想要的结果:
sorted = [{"#":"3", "files": [("example.out",0)]},
{"#":"1", "files": [("test.txt",1),("example.out",1)]},
{"#":"4", "files": [("test.txt",2)]},
{"#":"2", "files": [("other.txt",0),("test.txt",3)]}]
PS,可以用lambda做吗?
解决方案
正如已经指出的那样,鉴于您的数据的性质,您可能会得到不符合您的规则的条目组合。根据您的要求进行排序也不是一项简单的任务,因为每个节点都需要知道其他节点中的数据才能做出决定。
话虽如此,我已经给了它一个裂缝。虽然并不简单,但我可能过度考虑了这个过程。这也不是一个优雅的解决方案,也绝对不是一个有效的过程。我想在大型数据集上执行需要相当长的时间。
我已经用您的样本数据对其进行了测试,结果似乎很好。我添加了一些额外的数据,包括不能满足您的要求的数据,我觉得在这种情况下得到的订单就足够了。如果无法正确排序,将其更改为退出和/或导致错误会很简单。假设总是有正确的顺序,这应该有效。肯定需要更多测试:
class Node:
"""
A node representing the inner dictionary of files. Keeps rack of
lesser and greater nodes so that they can be placed into a list in appropriate order.
"""
def __init__(self, file_dict: dict):
self.file_dict = file_dict
self.files = {i[0]: i[1] for i in file_dict['files']}
self.greater_nodes = []
self.lesser_nodes = []
self.on_stack = False
self.in_list = False
def compare_nodes(self, other_node, file_name):
"""Compares the nodes to each other and lists each other in either their greater or lesser groups"""
if self.files[file_name] < other_node.files[file_name]:
self.lesser_nodes.append(other_node)
other_node.greater_nodes.append(self)
else:
self.greater_nodes.append(other_node)
other_node.lesser_nodes.append(self)
def place_node(self, node_list, lesser_list):
"""Places node in given list, but first checks for any greater node in the list and places those first"""
self.on_stack = True # If on stack and referenced as greater, place into list.
lesser_list += self.lesser_nodes
for node in self.greater_nodes:
if node not in lesser_list: # Don't go to nodes that are in any way lower than those on the stack.
if node.on_stack and not node.in_list:
node_list.append(node.file_dict)
node.in_list = True
node.on_stack = False
elif not node.in_list:
node.place_node(node_list, lesser_list)
if not self.in_list:
node_list.append(self.file_dict)
self.in_list = True
self.on_stack = False
def __repr__(self):
return f'{self.file_dict["#"]}'
class FileObj:
"""
Representation for each different file name.
Tracks nodes with common file name so that they can be appropriately compared.
"""
def __init__(self, name: str):
self.name = name
self.nodes = []
def add_node(self, new_node: Node):
"""Add another node to the list for the file object, making sure to
compare any new nodes to old based on file name."""
for old_node in self.nodes:
new_node.compare_nodes(old_node, self.name)
self.nodes.append(new_node)
def place_nodes(self, node_list):
"""Place all nodes into a given list."""
# Sorts nodes first (shouldn't be necessary in most cases, as they should all have valid relational data).
self.nodes.sort(key=lambda x: x.files[self.name])
for node in self.nodes:
if not node.in_list:
node.place_node(node_list, [])
def __repr__(self):
return f"{self.name} : {self.nodes}"
def sort_function(unsorted_list):
# Get dict of file objects.
file_dict = {str(y[0]): FileObj(y[0]) for x in unsorted_list for y in x['files']}
file_order = sorted([x for x in file_dict.keys()]) # Reference of file names in sorted order.
# Get list of dicts from the unsorted list as node-objects.
node_list = [Node(x) for x in unsorted_list]
# Get nodes to assign themselves to file_objects
for node in node_list:
for file in node.files.keys():
file_dict[file].add_node(node)
# Go through file_order to start placing nodes in lexicographical order.
final_list = []
for file_name in file_order:
file_obj = file_dict[file_name]
file_obj.place_nodes(final_list)
# Print results to check.
print(final_list, "\n")
for d in final_list:
print(d)
def main():
unsorted_list = [{"#": "1", "files": [("test.txt", 1), ("example.out", 1)]},
{"#": "2", "files": [("other.txt", 0), ("test.txt", 3)]},
{"#": "3", "files": [("example.out", 0)]},
{"#": "4", "files": [("test.txt", 2)]}]
sort_function(unsorted_list)
if __name__ == '__main__':
main()
推荐阅读
- sql - 如何复制嵌套 SQL 表(实现更改历史记录)
- asp.net - (Asp.net核心)为什么我显示另一个不是索引的视图时布局样式不起作用
- mongodb - 具有有效 mongo URL 的 pymongo ServerSelectionTimeoutError
- django - 在 Django 模板中将卡片组划分为行的最佳方法 - Django
- perl - 从 perl 中的二进制文件中获取十进制值
- python - Python 中在另一个类中访问 self 的最佳实践
- android - Android - layout_weight - LinearLayout 中的大小问题
- django - Django:ManyToManyField 中间模型错误
- javascript - 有没有办法默认允许在隐身模式下扩展?
- r - 打印行以获得最大列值