Python:有效地访问特定对象,就好像它是一个字典

时间:2016-06-25 01:45:05

标签: python class dictionary graph graph-theory

目前我正在用Python编写一些图论理论,此时就是DFS。我创建了一个Node类,它包含Node的名称(如果你愿意,它包含顶点)和一个字符串列表,其中包含与之连接的所有其他节点的名称。

# Simplified for the sake of the question.
class Node:
    """ Node using an adjacency list to know which other
        nodes it's connected to. """
    def __init__(self, name, edges):
        self.name = name # Letter normally, like C.
        self.edges = sorted(edges) # List of letters for Nodes.
        self.visited = False

我发现尝试包含一个Node对象列表而不是每个节点名称的字符串是不现实的,因为这将涉及在创建连接节点列表之前确保所有节点都存在。

这意味着当我想查找一个节点做DFS这样的事情时,我需要一个这样的函数:

def getNode(nodeLetter, nodes):
    for node in nodes:
        if node.name == nodeLetter:
            return node
    return None

此函数可以取O(| V |)时间,与顶点数成比例。这将随着时间的推移而积累,因为在整个探索中我将需要访问每个顶点,使得总复杂度为O(| V | ^ 2)。如果我使用了字典,例如:

{"A": ["C", "E"], "E", ["A"]}

我可以有恒定的时间查找。这当然会引入一些问题,例如我存储额外属性的地方,如visited,以及前后数字,以及我可能需要的任何其他内容。

我怎样才能在这里得到最好的两个世界,一个班级的整洁和一个字典的效率。有没有给定键的类的有效词典?热衷于学习如何最好地解决这个问题。

2 个答案:

答案 0 :(得分:1)

你可以继承大多数Python类型(除了NoneType,据我所知,还有GeneratorType)。

做这样的事情:

class MyDict(dict):
    '''This walks and talks like a dict'''

    def do_something(self):
        print(repr(self))

您可以随意扩展它,您甚至可以覆盖__getitem____setitem__魔术方法来控制数据在dict中的访问和存储方式。

在这种情况下,我们可以实例化dict,并充分利用这两个世界:

>>> mydict = MyDict([('a', 3)])
>>> kwd_init = MyDict(a=3)
>>> dict_init = MyDict({'a': 3})
>>> mydict.do_something()
{'a': 3}

在您的特定情况下,只需将其应用于节点架构即可。

class Node(dict):
    '''Defines a node object'''

    get_node = dict.__getitem__
    set_node = dict.__setitem__

现在我们可以扩展它来存储以前访问过的节点,最有可能是使用列表。

class Node(dict):
    '''Defines a node object'''

    def __init__(self, *args, **kwds):
        super(Node, self).__init__(*args, **kwds)

        self.visited = []

    def __getitem__(self, name):
        '''Get the node but also store it as the last visited item'''

        value = dict.__getitem__(self, name)
        self.visited.append(name)
        return value

    get_node = __getitem__
    set_node = dict.__setitem__

如果要为受访节点提供持续的查找时间,请使用集合。如果您想要两者,请尝试自定义OrderedSet

不是太难了,是吗?

答案 1 :(得分:0)

为什么你不创建一个将字母链接到节点而不是遍历所有节点的dict,只要你想知道哪个节点有字母。

所以这个想法很简单

  • 使用字母作为键创建dic,将节点创建为值
  • 并且每当您创建节点时,将其添加到dict
  • 当你想知道哪个节点有字母时只查询dict是O(1)
通过这种方式你可以消除这个循环

def getNode(nodeLetter, nodes):
    for node in nodes:
        if node.name == nodeLetter:
            return node
    return None

到这个

def getNode(nodeLetter, nodesandlettersdict):
    return nodesandlettersdict(nodeLetter)