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:tupleslist引用一个文件及其rev.例如,("test.txt",1)是rev为1的test.txt文件。

需要对对象unsorted进行排序,使其元素的顺序如下:

  1. 按图书名称排序
  2. 如果多个元素有相同的图书名称,次要版本优先

下面是想要的结果:

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()

示例代码的外部字典似乎是多余的。它包含一个没有键的列表。如果你去掉列表括号,你就得到了字典的字典,但仍然没有键,所以它是无效的。

但是如果你去掉字典外的大括号,那么你就剩下了一个字典列表,你完全可以用lambda:

对它进行排序
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)]}]

unsorted_list.sort(key=lambda x: x['files'][-1][1])

使用lambda x,其中x引用列表中的每个字典。然后访问字典x['files']的'files'元素,然后访问文件内部列表[-1]中的最后一个元素,最后访问内部元组[1]的第二个元素。然后将其作为键,以便对最外层的列表进行排序。

测试与给定的代码,它似乎工作良好。当然,列表中的任何其他条目都必须与现有结构一致,否则它将无法工作。

如果您确实需要外部字典,并使其结构适当,这应该会有所帮助。