按照实际上是列表的值对python中的字典进行排序

时间:2019-04-10 22:42:47

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

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

  

{“ 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']]

3 个答案:

答案 0 :(得分:3)

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

您可以通过嵌套列表理解来做到这一点:

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_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']]

答案 1 :(得分:1)

您可以使用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和用lambda替换operator.itemgetter

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']]

答案 2 :(得分:1)

您可以将每个边缘表示为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']] 过滤边缘重复项:

Number.isInteger(month) && month >= 1 && month <= 12