迭代 3 个字典(关注速度)

Iterating over 3 dictionaries (focus on speed)

我是 Python 的新手,正在使用 NetworkX 构建图表。

在我的脚本中,我有三个字典,它们可能需要相互嵌套:

  1. dict1={'Node ID':1} -> dict1={'0':1,'1':1,'2':1, ...}
  2. dict2={'Node ID':G.neighbors(节点 ID)} -> dict2={'0':[1,2,4], ...}
  3. dict3={'Node ID':状态} -> dict3={'1':1, '2':0, '4':1}

要crystal清楚,dict1告诉我节点是活动的(1)还是失败的(0)[在这种情况下,dict1的所有节点都是活动的]; dict2包含与dict1的每个节点相连的所有节点; dict3 告诉我连接到 dict1 每个节点的所有节点是活动的 (1) 还是失败的 (0)。

我的问题。我希望能够对节点之间的交互进行建模。这意味着如果节点 0 处于活动状态 (status=1),并且有 3 个节点连接到它,如果所有节点都失败 (status=0),则节点 0 失败也。如果只有一个连接的节点仍然处于活动状态,则节点 0 也仍然处于活动状态。

我的尝试这是我设想的理论流程图,但是不知道怎么翻译成Python,也不知道这个是不是是最好的方法:

  1. 遍历dict1;
  2. 对于dict1的每个键,获取dict2的值与dict1的当前键关联;
  3. 对于在 dict2 中找到的每个值,在 dict3 中检查它们的状态是 0 还是 1(在 dict2 中找到的值成为 dict3 的键);
  4. 如果(且仅当)以这种方式找到的所有 dict3 键都为 0,则将与当前 dict1 键关联的值更改为 0。

PS:这个流程图是要应用于10000个节点的网络,所以重点是速度。嵌套 3 个 for 循环听起来像是一个(非常)糟糕的主意,所以我希望有一个不同的解决方案。

对于无法将其放入正确的代码中,我深表歉意,但我真的很挣扎。非常感谢!

正如 JoshRomRock 在评论中所建议的那样,您可以像这样创建一个 class:

class Node(object):
    def __init__(self, node_id, neighbours, status):
        # neighbours could be a list of other Node objects
        self.node_id = node_id
        self.neighbours = neighbours
        self.status = status

    def neighbours_status(self):
        # this method would return a list of tuples, 
        # where first tuple elem is node_id and the second is its status
        return [(n.node_id, n.status) for n in self.neighbours]

然后像这样在您的代码中使用它:

 my_nodes = set()  # create set
 my_nodes.add(Node(0, [], 1))  # add a node with no neighbours
 # add some more nodes here ...

 for node in my_nodes:
     # do something with node.status, or node.node_id, or node.neighbours_status()

我认为这可能是一个 "X/Y" 问题。我不相信您尝试实施解决方案的方式是最好的,但我将尝试回答您提出的问题。您可能会问另一个参数稍微宽泛的问题。

这是我认为您所描述内容的伪代码:

initialize nodes
create some initial set_of_nodes such that all have status active.
for node in set_of_nodes:
    if node has no neighbors:
        move on
    else:
        has_active_neighbor = False
        for neighbor in neighbors(node):
            add neighbor to set_of_nodes
            if neighbor's status is active:
                has_active_neighbor = True
        if has_active_neighbor = False:
            node's status becomes inactive.

此代码存在一些潜在问题。您可能会遍历并在迭代时更改某些节点的状态,这意味着如果您再次检查它们,某些已经处理过的节点将失败。所以你正在寻找某种级联。您可能希望循环遍历节点,直到没有任何更改发生。此外,在循环遍历集合时添加到集合中有点奇怪。这在 Python 中有点禁忌(通常也是如此)。因此,我正在创建一组您要添加的新节点。因此,根据您尝试研究的系统规则,这可能不是最好的。另外,我不明白为什么你只从一个子集而不是整个网络开始你的 dict1。

这里是 networkx 的实现。我将遍历它直到没有任何变化发生。

import networkx as nx

# code here to define graph, assign initial statuses, and create node_set
# node attributes can be defined in several ways (one appears below)

changes = True
while changes:
    changes = False
    added_nodes = set()
    for x in node_set:
        if G.degree(x)==0 or G.node[x]['status'] == 'failed':
            continue  #nothing to see here, move on.
        else:
            has_active_neighbor=False
            for neighbor in G.neighbors(x):
                added_nodes.add(neighbor) #put it here even if it is already in node_set
                if G.node[neighbor]['status'] == 'active':
                    has_active_neighbor = True
                    break
            if not has_active_neighbor:
                changes = True
                G.node[x]['status'] = 'failed'
    if node_set.difference(added_nodes):  #True if any new nodes:
        node_set = node_set.union(added_nodes)
        changes = True

#everything is done now - here's the dictionary of statuses:
statuses = nx.get_node_attributes(G, 'status')