简体   繁体   English

如何将对列表转换为字典,每个元素作为配对值列表的键?

[英]How do I convert a list of pairs into a dictionary with each element as a key to a list of paired values?

I'm doing coursework which involves graphs. 我正在做涉及图表的课程。 I have edge lists E=[('a','b'),('a','c'),('a','d'), ('b','c') etc. ] and I want to a function to convert them into adjacency matrices in the form of dictionaries {'a':['b','c','d'], 'b':['a', etc. } so that I can use a function that only inputs these dictionaries. 我有边缘列表E = [('a','b'),('a','c'),('a','d'),('b','c')等等。我想要一个函数将它们转换成字典形式的邻接矩阵{'a':['b','c','d'],'b':['a'等}}所以我可以使用只输入这些词典的函数。

My main issue is I can't figure out how to use a loop to add key:values without just overwriting the lists. 我的主要问题是我无法弄清楚如何使用循环来添加键:值而不只是覆盖列表。 A previous version of my function would output [] as all values because 'f' has no connections. 我的函数的先前版本将输出[]作为所有值,因为'f'没有连接。

I've tried this: 我试过这个:

V = ['a','b','c','d','e','f']
E=[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

def EdgeListtoAdjMat(V,E):
    GA={}
    conneclist=[]
    for v in V:
        for i in range(len(V)):
            conneclist.append([])
            if (v,V[i]) in E:
                conneclist[i].append(V[i])
    for i in range(len(V)):
        GA[V[i]]=conneclist[i]
    return(GA)

EdgeListtoAdjMat(V,E) outputs: EdgeListtoAdjMat(V,E)输出:

{'a': [], 'b': ['b'], 'c': ['c', 'c'], 'd': ['d', 'd', 'd'], 'e': [], 'f': []}

whereas it should output: 而它应该输出:

{'a':['b','c','d'],
'b':['a','c','d'],
'c':['a','b','d'],
'd':['a','b','c'],
'e':[],
'f':[]
}

The logic of what you're trying to achieve is actually quite simple: 你想要实现的逻辑实际上非常简单:

V = ['a','b','c','d','e','f']
E=[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

result = {}
for elem in V:
     tempList = []
     for item in E:
          if elem in item:
               if elem == item[0]:
                    tempList.append(item[1])
               else:
                    tempList.append(item[0])
     result[elem] = tempList
     tempList = []

print(result)

Result: 结果:

{'a': ['b', 'c', 'd'], 'b': ['a', 'c', 'd'], 'c': ['a', 'b', 'd'], 'd': ['a', 'b', 'c'], 'e': [], 'f': []}

For every element in V , perform a check to see whether that element exists in any tuple in E . 对于V每个元素,执行检查以查看该元素是否存在于E中的任何元组中。 If it exists, then take the element that together form a pair on that tuple and append to a temporary list. 如果它存在,则将该元素组合在一起形成一对,并附加到临时列表。 After checking every element in E , update the result dictionary and move to the next element of V until you're done. 检查E每个元素后,更新result字典并移至V的下一个元素,直到完成为止。

To get back to your code, you need to modify it as following: 要返回代码,您需要按以下方式修改它:

def EdgeListtoAdjMat(V,E):
    GA={}
    conneclist=[]
    for i in range(len(V)):
        for j in range(len(V)):
            # Checking if a pair of two different elements exists in either format inside E. 
            if not i==j and ((V[i],V[j]) in E or (V[j],V[i]) in E):
                conneclist.append(V[j])
        GA[V[i]]=conneclist
        conneclist = []
    return(GA)

A more efficient approach is to iterate through the edges and append to the output dict of lists the vertices in both directions. 一种更有效的方法是迭代边缘并将列表的输出字典附加到两个方向上的顶点。 Use dict.setdefault to initialize each new key with a list. 使用dict.setdefault使用dict.setdefault初始化每个新键。 And when the iterations over the edges finish, iterate over the rest of the vertices that are not yet in the output dict to assign to them empty lists: 当边缘上的迭代结束时,迭代尚未出现在输出dict中的其余顶点,为它们分配空列表:

def EdgeListtoAdjMat(V,E):
    GA = {}
    for a, b in E:
        GA.setdefault(a, []).append(b)
        GA.setdefault(b, []).append(a)
    for v in V:
        if v not in GA:
            GA[v] = []
    return GA

so that given: 所以给出:

V = ['a', 'b', 'c', 'd', 'e', 'f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

EdgeListtoAdjMat(V, E)) would return: EdgeListtoAdjMat(V, E))将返回:

{'a': ['b', 'c', 'd'], 'b': ['a', 'c', 'd'], 'c': ['a', 'b', 'd'], 'd': ['a', 'b', 'c'], 'e': [], 'f': []}

Since you already have your list of vertices in V, it is easy to prepare a dictionary with an empty list of connections. 由于您已经在V中有了顶点列表,因此很容易准备一个带有空连接列表的字典。 Then, simply go through the edge list and add to the array on each side: 然后,只需浏览边缘列表并添加到每一侧的数组:

V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

GA = {v:[] for v in V}
for v1,v2 in E:
    GA[v1].append(v2)
    GA[v2].append(v1)

I think your code is not very pythonic, you could write a more readable code that is simpler to debug and also faster since you are using python's built-in libraries and numpy's indexing. 我认为你的代码不是非常pythonic,你可以编写一个更易读的代码,更简单的调试,也更快,因为你使用python的内置库和numpy的索引。

def EdgeListToAdjMat(V, E):
    AdjMat = np.zeros((len(V), len(V)))  # the shape of Adjancy Matrix
    connectlist = {
        # Mapping each character to its index
        x: idx for idx, x in enumerate(V)
    }
    for e in E:
        v1, v2 = e
        idx_1, idx_2 = connectlist[v1], connectlist[v2]
        AdjMat[idx_1, idx_2] = 1     
        AdjMat[idx_2, idx_1] = 1

    return AdjMat

If you'd consider using a library, networkx is designed for these type of network problems: 如果您考虑使用库, networkx是针对这些类型的网络问题而设计的:

import networkx as nx 

V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

G=nx.Graph(E)
G.add_nodes_from(V)
GA = nx.to_dict_of_lists(G)

print(GA)

# {'a': ['c', 'b', 'd'], 'c': ['a', 'b', 'd'], 'b': ['a', 'c', 'd'], 'e': [], 'd': ['a', 'c', 'b'], 'f': []}

You can convert the edge list to the map using itertools.groupby 您可以使用itertools.groupby将边列表转换为地图

from itertools import groupby
from operator import itemgetter

V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

# add edge in the other direction. E.g., for a -> b, add b -> a
nondirected_edges = E + [tuple(reversed(pair)) for pair in E]

# extract start and end vertices from an edge
v_start = itemgetter(0)
v_end = itemgetter(1)

# group edges by their starting vertex
groups = groupby(sorted(nondirected_edges), key=v_start)
# make a map from each vertex -> adjacent vertices
mapping = {vertex: list(map(v_end, edges)) for vertex, edges in groups}

# if you don't need all the vertices to be present
# and just want to be able to lookup the connected
# list of vertices to a given vertex at some point
# you can use a defaultdict:
from collections import defaultdict
adj_matrix = defaultdict(list, mapping)

# if you need all vertices present immediately:
adj_matrix = dict(mapping)
adj_matrix.update({vertex: [] for vertex in V if vertex not in mapping})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM