【问题标题】:Mapping from a pair or names to a value in Python从一对或名称映射到 Python 中的值
【发布时间】:2014-02-24 04:01:44
【问题描述】:

我有一个应用程序,其中有一组命名节点。对于每对节点,我想存储它们的连接值。节点会随着时间的推移来来去去,所以我不能一开始就初始化一个“数组”。名称不是连续整数,而是任意对象 ID 或字符串名称。

我需要能够做到:

lookup(name1, name2) -> value

还有

set(name1, name2, value)

并且,当一个新节点加入时,要做的事情:

set(newname, [all other nodes], default_value)

假设对于每一对,方向无关紧要。即,(name1,name2) 应该与 (name2,name1) 具有相同的值。

最明显的 Python 实现似乎是一个两级字典:

{ name1 : { name2: value, name3:value}, name2: {name1:value, name3:value}, ... etc. }

这是最好的方法吗?

更新

在 Python 中使用带有对作为键的 dict 的建议可能更好。然而,我也有一个附带限制,能够将数据集导出和导入为列表列表(为了支持 Simics 模拟器中的状态序列化) - 为此,两级映射是很自然。但我想这对也会在那里工作。实际上,很难说什么更好。

【问题讨论】:

  • 这个数据结构看起来很像一个图,尽管图对于您的应用程序来说可能是多余的。看看networkx或igraph...
  • 它是一个图,但是是一个全连接图,所以一般的图可能是矫枉过正。

标签: python arrays dictionary


【解决方案1】:

您可以使用frozenset() 键:

{frozenset([name1, name2]): value, frozenset([name2, name3]): other_value}

优点是frozenset()对象可以作为key,节点的顺序无关紧要; frozenset([name1, name2]) 等于 frozenset([name2, name1])

要获取所有节点的列表,您必须使用:

all_nodes = reduce(frozenset.union, yourdict.keys())

如果这是 Python 2,请改用 yourdict.iterkeys()。然后,您可以从中生成所有可能的组合以设置默认值:

from itertools import permutations:

for name1, name2 in permutations(all_nodes, r=2):
    key = frozenset([name1, name2])
    if key not in yourdict:
        yourdict[key] = default_value

或者,如果您将整个结构包装在一个类中(这可能是一个好主意),您可以添加一个额外的索引来跟踪所使用的节点,从而在您更新实例时保持该索引是最新的。

【讨论】:

    【解决方案2】:

    或者,您可以使用带有元组作为键的字典

    {(name1, name2) : value, (name1, name3) : value, (name2, name1) : value, ...}
    

    而不是

    {name1 : {name2 : value, name3 : value}, name2 : {name1 : value, ...}, ... etc.}
    

    然后操作将如下所示:

    values = {(name1, name2) : value, (name1, name3) : value, (name2, name1) : value, ...}
    
    def lookup(name1, name2):
        return values[name1, name2]
    
    def set(name1, name2, value):
        values[name1, name2] = value
        values[name2, name1] = value  # for symmetry
    

    P.S.不要为默认连接值浪费内存,您可以修改查找,如下所示:

    def lookup(name1, name2):
       return values.get((name1, name2), default_value)
    

    但在这种情况下,您将获得default_value 用于不在集合中的节点。

    【讨论】:

    • 但这不会处理 (name2, name1)(name1, name2) 相同。
    • @MartijnPieters,如果我们使用刚刚定义的lookupset 操作,从外部的角度来看没有区别。当然 fronzensets 仍然可以用来将已用内存减半。
    • 这很可能和我所做的一样有效;但最终结果在语法上非常相似。我得到 foo[name1][name2] 而不是 foo[name1,name2]。
    • @jakobengblom2,但在这种情况下,处理不存在的节点名称会更容易。
    猜你喜欢
    • 2018-03-11
    • 2012-04-18
    • 1970-01-01
    • 2020-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-06
    • 2010-11-15
    相关资源
    最近更新 更多