迭代3个词典(专注于速度)

时间:2015-10-26 15:48:46

标签: python for-loop dictionary nested-loops networkx

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

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

  1. dict1 = {'节点ID':1} - > dict1={'0':1,'1':1,'2':1, ...}
  2. dict2 = {'节点ID':G.neighbors(节点ID)} - > dict2={'0':[1,2,4], ...}
  3. dict3 = {'节点ID':状态} - > dict3={'1':1, '2':0, '4':1}
  4. 为了清楚起见,dict1告诉我节点是活动的(1)还是失败的(0)[在这种情况下,dict1的所有节点都是活动的]; dict2包含连接到dict1的每个节点的所有节点; dict3告诉我连接到dict1的每个节点的所有节点是活动的(1)还是失败的(0)。

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

    我的尝试。这是我设想的理论流程图,但我不知道如何将其翻译成Python,也不知道这是否是最佳方法:

    1. 循环通过dict1;
    2. 对于dict1的每个键,获取与dict1的当前键关联的dict2的值;
    3. 对于在dict2中找到的每个值,检查dict3,如果它们的状态为0或1(在dict2中找到的值成为dict3的键);
    4. 如果(且仅当)所有以这种方式找到的dict3键取为0,则将与当前dict1键关联的值更改为0.
    5. PS:此流程图将应用于10000个节点的网络,因此重点实际上是速度。嵌套3 for循环可能听起来像(非常)坏主意,所以我将不胜感激。

      我为无法将其放入正确的代码而道歉,但我真的很挣扎。非常感谢!

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

我认为这可能是一个"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')