【问题标题】:Sorting dictionaries in python by values that are actually lists按实际上是列表的值对python中的字典进行排序
【发布时间】:2019-04-10 22:42:47
【问题描述】:

如果给我一个字典来表示一个图,其中顶点是键,值是列表,其条目同时包含相邻顶点和两个顶点之间的权重,我如何以递增的顺序返回边列表没有重复?例如,我可能会得到以下字典...:

{"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C ": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}。

此外,我只允许导入复制库,因此我可以复制一个列表并使用 deepcopy() 创建具有相同元素的新对象。

现在,我正在尝试将字典转换为列表,因为我认为对列表中的元素进行排序并删除重复的边缘可能会更容易。所以目前我有以下内容(图表是字典,在这种情况下是我上面提供的那个)......

def edge_get(graph):

    input_list = []
    sorted_list = []

    for key, value in graph.items():
        temp = [key,value]
        input_list.append(temp)

    print(input_list)

这打印出来了...

[['A', [['B', 10], ['D', 5]]], ['B', [['A', 10], ['C', 5]] ], ['C', [['B', 5], ['D', 15]]], ['D', [['C', 15], ['A', 5]]]]

我想让它输出:

[['A', 'B', 10], ['A', 'D', 5], ['B', 'A', 10], ['B', 'C', 5 ],...

我想如果我能像这样得到它,我可以比较每个列表的第三个元素,在列表中,如果它们相同,检查其他元素是否匹配(相同的边缘)。基于此,我可以将其添加到最终列表中,或者忘记它并继续前进。

对于这个例子,最终目标是:

[['A', 'D'], ['B', 'C'], ['A', 'B'], ['C', 'D']]

【问题讨论】:

    标签: python python-3.x list dictionary nested-lists


    【解决方案1】:

    因此,您有一个将图形表示为邻接列表的字典,并且您希望将该邻接列表转换为边列表。

    您可以使用嵌套列表推导来做到这一点:

    graph = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
    edges = [(src, dst, weight) for src, adjs in graph.items() for dst, weight in adjs]
    # edges = [('A', 'B', 10), ('A', 'D', 5), ('B', 'A', 10), ('B', 'C', 5), ('C', 'B', 5), ('C', 'D', 15), ('D', 'C', 15), ('D', 'A', 5)]
    

    然后您可以通过转换为字典来消除重复的边,请注意,如果您有重复的边具有冲突的权重,这将任意选择一个权重:

    uniques = {frozenset([src, dst]): weight for src, dst, weight in edges}
    # uniques = {frozenset({'B', 'A'}): 10, frozenset({'A', 'D'}): 5, frozenset({'B', 'C'}): 5, frozenset({'C', 'D'}): 15}
    

    然后用 sorted 对边进行排序:

    sorted_uniques = sorted(uniques.items(), key=lambda v: v[1])
    # sorted_uniques = [(frozenset({'A', 'D'}), 5), (frozenset({'C', 'B'}), 5), (frozenset({'A', 'B'}), 10), (frozenset({'C', 'D'}), 15)]
    

    最后,要获得所需结构的结果,您只需执行以下操作:

    result = [sorted(e) for e, weight in sorted_uniques]
    # result = [['A', 'D'], ['B', 'C'], ['A', 'B'], ['C', 'D']]
    

    【讨论】:

      【解决方案2】:

      您可以将每条边表示为 frozenset 并在 set 的帮助下过滤边重复:

      G = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
      
      edges = {(frozenset((k, i)), j) for k, v in G.items()
                                      for i, j in v}
      [sorted(i) for i, _ in sorted(edges, key=lambda x: x[1])]
      # [['B', 'C'], ['A', 'D'], ['A', 'B'], ['C', 'D']]
      

      【讨论】:

        【解决方案3】:

        您可以使用itertools.product 生成键与每个相关子列表的组合。如果您对每个组合的字符串组件进行排序和解包,那么您将获得您正在寻找的初始输出。从那里,您可以首先按权重值对整个列表进行排序,然后按顶点排序,以获得有序列表。如果您使用步长值对该列表进行切片,则可以删除重复项。然后,您可以删除权重值以获得最终输出的对列表。

        您可以进一步整合以下步骤,但这会通过您的问题中概述的步骤,以希望使其更容易遵循。

        from itertools import product
        from operator import itemgetter
        
        d = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
        
        combos = [[*sorted([c1, c2]), n] for k, v in d.items() for c1, [c2, n] in product(k, v)]
        print(combos)
        # [['A', 'B', 10], ['A', 'D', 5], ['A', 'B', 10], ['B', 'C', 5], ['B', 'C', 5], ['C', 'D', 15], ['C', 'D', 15], ['A', 'D', 5]]
        
        ordered = sorted(combos, key=itemgetter(2, 0, 1))[::2]
        print(ordered)
        # [['A', 'D', 5], ['B', 'C', 5], ['A', 'B', 10], ['C', 'D', 15]]
        
        pairs = [o[:-1] for o in ordered]
        print(pairs)
        # [['A', 'D'], ['B', 'C'], ['A', 'B'], ['C', 'D']]
        

        编辑(没有导入):

        每条评论强调在您的解决方案中使用导入的限制,这里是原始版本的修改版本。不同之处在于将 itertools.product 替换为完成相同任务的列表理解,并将 operator.itemgetter 替换为 lambda。

        d = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
        
        combos = [[*sorted([k, c]), n] for k, v in d.items() for c, n in v]
        print(combos)
        # [['A', 'B', 10], ['A', 'D', 5], ['A', 'B', 10], ['B', 'C', 5], ['B', 'C', 5], ['C', 'D', 15], ['C', 'D', 15], ['A', 'D', 5]]
        
        ordered = sorted(combos, key=lambda x: (x[2], x[0], x[1]))[::2]
        print(ordered)
        # [['A', 'D', 5], ['B', 'C', 5], ['A', 'B', 10], ['C', 'D', 15]]
        
        pairs = [o[:-1] for o in ordered]
        print(pairs)
        # [['A', 'D'], ['B', 'C'], ['A', 'B'], ['C', 'D']]
        

        【讨论】:

        • OP 不允许import
        猜你喜欢
        • 2021-08-25
        • 1970-01-01
        • 2011-02-22
        • 1970-01-01
        • 2013-04-15
        • 2010-11-15
        • 2018-11-27
        • 2011-01-16
        相关资源
        最近更新 更多