如何从字典字典中删除所有出现的项目?

时间:2014-06-14 19:07:38

标签: python dictionary

我有一本字典词典。键是图中的节点。例如,让我们假设图中的节点i由字典中的键i表示。与该键对应的值也是字典,其中键是图中节点i的邻居。这些键具有默认值1.让我们考虑以下示例 -

图中的节点是 - [1,2,3,4,5,6]

邻居:

1->[2,4,5,6]

2->[3]

3->[4,6]

4->[1,6]

5->[1]

6->[1,3,4]

所以字典字典看起来像这样:

{1:{2:1,4:1,5:1,6:1},2:{3:1},3:{4:1,6:1},4:{1:1,6:1},5:{1:1},6:{1:1,3:1,4:1}}

现在,在我尝试实现的算法的不同阶段,我需要从其他节点的邻居列表中删除所有出现的节点x。如果x = 4,则删除后,字典字典应如下所示:

{1:{2:1,5:1,6:1},2:{3:1},3:{6:1},4:{1:1,6:1},5:{1:5},6:{1:1,3:1}}

我使用字典而不是列表字典来使删除有效。但它仍然很昂贵。

这样做效率最高的是什么?

3 个答案:

答案 0 :(得分:3)

使用词典理解:

{ok: {ik: iv for ik, iv in ov.iteritems() if ik != x} 
 for ok, ov in yourdict.iteritems()}

这会重建您的词典,而省略内部词典中与x匹配的所有键。

在Python 3中替换iteritems() items()

演示:

>>> yourdict = {1:{2:1,4:1,5:1,6:1},2:{3:1},3:{4:1,6:1},4:{1:1,6:1},5:{1:5},6:{1:1,3:1,4:1}}
>>> x = 4
>>> {ok: {ik: iv for ik, iv in ov.iteritems() if ik != x} 
...  for ok, ov in yourdict.iteritems()}
{1: {2: 1, 5: 1, 6: 1}, 2: {3: 1}, 3: {6: 1}, 4: {1: 1, 6: 1}, 5: {1: 5}, 6: {1: 1, 3: 1}}

答案 1 :(得分:2)

您选择的结构可能不是最有效的结构。套装可能只适合账单。

我不太明白你的连接是箭头式的单向连接还是双向连接。我假设单向连接,因为2是1的邻居,但反之亦然。如果是这种情况,我们需要跟踪“从”和“到”。

我已修改您的代码以使用集合而不是字典来提高效率。

pointing_to = {
    1: set([2,4,5,6]),
    2: set([3]),
    3: set([4,6]),
    4: set([1,6]),
    5: set([1]),
    6: set([1,3,4]) }

pointed_by = {
    1: set([4,5,6]),
    2: set([1]),
    3: set([2,6]),
    4: set([1,3,6]),
    5: set([1]),
    6: set([1,3,4]) }

(当然,pointed_by可以用一小段代码创建,我只是写出来展示这个想法。)

现在,如果您需要删除与节点tbr之间的所有连接:

# remove tbr from pointing_to lists of all neighbours pointing to tbr
# (connections from other nodes to tbr
for n in pointed_by[tbr]:
    pointing_to[n].remove(tbr)
# after this tar is pointed by no neighbour
pointed_by[tbr] = set()

# repeat for opposite direction (connections from tbr to other nodes)
for n in pointing_to[tbr]:
    pointed_by[n].remove(tbr)
pointing_to[tbr] = set()

这应该相对快速且易于理解。

如果只有双向连接,一个字典和上面代码的一半就足够了。


关于表现的几句话。

可以看出,这种方法的循环非常短。它仅通过要删除的节点一端的连接进行迭代。在该级别,连接总数无关紧要,也不是总点数。

然而,更深层次的集合和字典查找时间并不独立于这些字典和集合的大小。我的猜测是O(log n),其中n是点或连接的总数,但有人可能更了解实际的实现。

使用套装比使用字典要快一些,但差别很小,因为它们几乎与引擎盖下面的东西相同。简单的集合操作往往非常快。

我的猜测是,对于非常小的数据集,线性搜索方法更快,因为它们可能使用列表推导和c。使用更大的数据,这将更有效。

答案 2 :(得分:0)

这将在原地进行。您可以先使用copy.deepcopy将其作为副本。

t = {1:{2:1,4:1,5:1,6:1},
     2:{3:1},
     3:{4:1,6:1},
     4:{1:1,6:1},
     5:{1:5},
     6:{1:1,3:1,4:1}}

for k,v in t.iteritems(): 
    v.pop(4, None)     

print t 
{1: {2: 1, 5: 1, 6: 1},
 2: {3: 1},
 3: {6: 1},
 4: {1: 1, 6: 1},
 5: {1: 5},
 6: {1: 1, 3: 1}}

您可以将其封装为辅助函数:

def remove_node(graph, node, inplace=True):
    import copy
    temp_graph = copy.deepcopy(graph) if not inplace else graph
    for k,v in temp_graph.iteritems():
        v.pop(node, None)
    return temp_graph