1

使用tree = lambda: dedfaultdict(tree),我可以替换以下代码:

from collections import defaultdict

END = '$'
words = ['hi', 'hello', 'hiya', 'hey']

root = {}
for word in words:
  node = root
  for ch in word:
    node = node.setdefault(ch, {}) # <---- Code that can be replaced
  node[END] = None

和:

from collections import defaultdict

END = '$'
words = ['hi', 'hello', 'hiya', 'hey']

tree = lambda: defaultdict(tree)
root = tree()
for word in words:
  node = root
  for ch in word:
    node = node[ch] # <------ Replaced code
  node[END] = None

我真正想要的是每个字典节点都有一个对其父字典节点的反向引用。我可以这样做:

from collections import defaultdict

BACKREF, END = 'BACKREF', '$'
words = ['hi', 'hello', 'hiya', 'hey']

root = {}
for word in words:
  node = root
  for ch in word:
    node = node.setdefault(ch, {BACKREF: node}) # <---- Code I want to replace
  node[END] = None

(证明这有效:链接

所以,鉴于我能够用来tree = lambda: defaultdict(tree)替换

  • node = node.setdefault(ch, {})
  • node = node[ch]

有没有办法我可以使用修改后的版本tree = lambda: default(tree)来替换

  • node = node.setdefault(ch, {BACKREF: node})
  • 用更简单的东西,比如也许node = node[ch]

我试过类似的东西:

def tree():
  _ = defaultdict(tree)
  _[BACKREF] = ?
  return _
root = tree()
h = root['h']

但这需要tree知道哪个字典调用了对tree. 例如 in h = root['h']root['h']调用对treebecause his not yet in的调用roottree必须知道它是通过调用调用的root['h'],以便它可以执行h[BACKREF] = root. 有没有解决的办法?即使可以做到,这也是一个坏主意吗?

我知道反向引用在技术上意味着 trie 将有循环(而不是真正的树),但是我计划遍历 trie 的方式,这不会是一个问题。我想要反向引用的原因是,如果我想从 trie 中删除一个单词,它会很有用。例如,假设我有以下尝试:

特里

并且我在root['h']['e']['l']['l']['o']并且想'hello'从特里删除。我可以通过从root['h']['e']['l']['l']['o']toroot['h']['e']['l']['l']root['h']['e']['l']to回溯 trie 来做到这一点root['h']['e'](我在这里停下来是因为len(set(root['h']['e'].keys()) - {BACKREF}) > 1. 然后我可以简单地做del root['h']['e']['l'],我将切断'llo$''he'trie 仍然具有的意义'hey'。虽然有替代方案,但回溯 trie 将是反向引用非常容易。


上下文开启tree = lambda: defaultdict(tree)

使用:

from collections import defaultdict

tree = lambda: defaultdict(tree)
root = tree()

可以创建任意嵌套dict的 s。例如之后:

root['h']['i']
root['h']['e']['l']['l']['o']
root['h']['i']['y']['a']
root['h']['e']['y']

root看起来像:

{'h': {'i': {'y': {'a': {}}}, 'e': {'y': {}, 'l': {'l': {'o': {}}}}}}

这表示一棵看起来像这样的树: 使用https://www.cs.usfca.edu/~galles/visualization/Trie.html进行可视化特里

4

2 回答 2

2

您尝试实现的行为似乎更容易编写为类而不是函数。

from collections import defaultdict

class Tree(defaultdict):
    def __init__(self, backref=None):
        super().__init__(self.make_child)
        self.backref = backref
    def make_child(self):
        return Tree(backref=self)

用法:

>>> root = Tree()
>>> root['h'].backref is root
True
>>> root['h']['e'].backref is root['h']
True
于 2021-10-13T02:12:19.890 回答
2

解决方案 1

给同样{BACKREF: node}defaultdict

from collections import defaultdict

BACKREF, END = 'BACKREF', '$'
words = ['hi', 'hello', 'hiya', 'hey']

tree = lambda: defaultdict(tree, {BACKREF: node})
node = None
root = tree()
for word in words:
  node = root
  for ch in word:
    node = node[ch]
  node[END] = None

root节点有一个 backref None,如果麻烦可以删除。

解决方案 2

如果该代码是创建树节点的唯一代码(从我自己构建此类树的时间来看,这对我来说似乎很可能),那么上面的代码就可以正常工作。否则,您需要确保node指向正确的父节点。如果这是一个问题,这里有一个 dict(不是 defaultdict)子类的替代方案,它实现__missing__了在需要时自动创建带有 backrefs 的子类:

BACKREF, END = 'BACKREF', '$'
words = ['hi', 'hello', 'hiya', 'hey']

class Tree(dict):
    def __missing__(self, key):
        child = self[key] = Tree({BACKREF: self})
        return child

root = Tree()
for word in words:
  node = root
  for ch in word:
    node = node[ch]
  node[END] = None

也不给根一个 backref,并且作为一个 dict,它的字符串表示远没有 defaultdict 的那么混乱,因此更具可读性:

>>> import pprint
>>> pprint.pp(root)
{'h': {'BACKREF': <Recursion on Tree with id=2494556270320>,
       'i': {'BACKREF': <Recursion on Tree with id=2494556270400>,
             '$': None,
             'y': {'BACKREF': <Recursion on Tree with id=2494556270480>,
                   'a': {'BACKREF': <Recursion on Tree with id=2494556340608>,
                         '$': None}}},
       'e': {'BACKREF': <Recursion on Tree with id=2494556270400>,
             'l': {'BACKREF': <Recursion on Tree with id=2494556340288>,
                   'l': {'BACKREF': <Recursion on Tree with id=2494556340368>,
                         'o': {'BACKREF': <Recursion on Tree with id=2494556340448>,
                               '$': None}}},
             'y': {'BACKREF': <Recursion on Tree with id=2494556340288>,
                   '$': None}}}}

比较的defaultdict结果:

>>> pprint.pp(root)
defaultdict(<function <lambda> at 0x000001A13760BE50>,
            {'BACKREF': None,
             'h': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                              {'BACKREF': <Recursion on defaultdict with id=1791930855152>,
                               'i': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                {'BACKREF': <Recursion on defaultdict with id=1791930855312>,
                                                 '$': None,
                                                 'y': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                                  {'BACKREF': <Recursion on defaultdict with id=1791930912832>,
                                                                   'a': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                                                    {'BACKREF': <Recursion on defaultdict with id=1791930913232>,
                                                                                     '$': None})})}),
                               'e': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                {'BACKREF': <Recursion on defaultdict with id=1791930855312>,
                                                 'l': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                                  {'BACKREF': <Recursion on defaultdict with id=1791930912912>,
                                                                   'l': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                                                    {'BACKREF': <Recursion on defaultdict with id=1791930912992>,
                                                                                     'o': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                                                                      {'BACKREF': <Recursion on defaultdict with id=1791930913072>,
                                                                                                       '$': None})})}),
                                                 'y': defaultdict(<function <lambda> at 0x000001A13760BE50>,
                                                                  {'BACKREF': <Recursion on defaultdict with id=1791930912912>,
                                                                   '$': None})})})})
于 2021-10-13T02:29:23.227 回答