【问题标题】:Python - printing out a trie in alphabetically sorted order with a recursive functionPython - 使用递归函数按字母顺序打印出 trie
【发布时间】:2019-11-01 01:28:01
【问题描述】:

我正在通过 Bird、Klein 和 Loper 的 NLTK book 工作,但遇到了一个问题。我正在阅读这本书是为了丰富自己的个人生活,而不是为了上课。

我遇到的问题是 4.29:

编写一个递归函数,以按字母顺序漂亮地打印 trie,例如:

chair: 'flesh' ---t: 'cat' --ic: 'stylish' ---en: 'dog'

我正在使用书中的这段代码来创建 trie:

def insert(trie, key, value):
    if key:
        first, rest = key[0], key[1:]
        if first not in trie:
            trie[first] = {}
        insert(trie[first], rest, value)
    else:
        trie['value'] = value

trie = {}
insert(trie, 'chat', 'cat')
insert(trie, 'chien', 'dog')
insert(trie, 'chair', 'flesh')
insert(trie, 'chic', 'stylish')

我修改了来自 this discussion 的答案,该函数递归地遍历 trie 并提取完整的键和值:

def trawl_trie(trie):
    unsorted = []
    for key, value in trie.items():
        if 'value' not in key:
            for item in trawl_trie(trie[key]):
                unsorted.append(key + item)
        else:
            unsorted.append(': ' + value)

    return unsorted

但我无法使用递归来制作按字母顺序排列的列表,也无法弄清楚如何使用递归来替换键的重复部分。我能做的最好的事情是创建一个辅助函数来遍历上述函数的结果:

def print_trie(trie):

    # sort list alphabetically
    alphabetized = list(sorted(set(trawl_trie(trie))))


    print(alphabetized[0])

    # compare the 2nd item ~ to the previous one in the list.
    for k in range(1, len(alphabetized)):
        # separate words from value
        prev_w, prev_d = (re.findall(r'(\w+):', alphabetized[k - 1]), re.findall(r': (\w+)', alphabetized[k - 1]))
        curr_w, curr_d = (re.findall(r'(\w+):', alphabetized[k]), re.findall(r': (\w+)', alphabetized[k]))
        word = ''

        # find parts that match and replace them with dashes
        for i in range(min(len(prev_w[0]), len(curr_w[0]))):
            if prev_w[0][i] == curr_w[0][i]:
                word += prev_w[0][i]

        curr_w[0] = re.sub(word, '-' * len(word), curr_w[0])
        print(curr_w[0] + ": " + str(curr_d[0]))

这将是输出:

print_trie(trie)

chair: flesh
---t: cat
--ic: stylish
---en: dog

有谁知道用一个递归函数是否可以得到相同的结果?或者我被困在使用递归函数来遍历 trie 时,使用第二个辅助函数来让一切看起来都很好?

干杯,

  • MC

【问题讨论】:

    标签: python recursion trie nltk-book


    【解决方案1】:
    def insert(trie, key, value):
        """Insert into Trie"""
        if key:
            first, rest = key[0], key[1:]
            if first not in trie:
                trie[first] = {}
            insert(trie[first], rest, value)
        else:
            trie['value'] = value
    
    def display(trie, s = ""):
      """Recursive function to Display Trie entries in alphabetical order"""
      first = True
      for k, v in sorted(trie.items(), key = lambda x: x[0]):
        # dictionary sorted based upon the keys
        if isinstance(v, dict):
          if first:
            prefix = s + k          # first to show common prefix
            first = False
          else:
            prefix = '-'*len(s) + k  # dashes for common prefix
    
          display(v, prefix)   # s+k is extending string s for display by appending current key k
        else:
          print(s, ":", v)  # not a dictionary, so print current   # not a dictionary, so print current string s and value
    
    # Create Trie
    trie = {}
    insert(trie, 'chat', 'cat')
    insert(trie, 'chien', 'dog')
    insert(trie, 'chair', 'flesh')
    insert(trie, 'chic', 'stylish')
    
    #Display Use Recursive function (second argument will default to "" on call)
    display(trie)
    

    输出

    chair : flesh
    ---t : cat
    --ic : stylish
    ---en : dog
    

    【讨论】:

    • 感谢您的回复,Darryl,但我认为输出应该略有不同。即,如果键的开头已经打印,则字符应替换为破折号。例如,椅子:肉; ---t:猫; --ic:时尚; ---zh: 狗。
    • @Sturzgefahr--谢谢。抱歉,我之前没有理解破折号的用途。您的帖子刚刚提到“编写一个递归函数,该函数可以按字母顺序漂亮地打印一个 trie,例如:”,但没有解释破折号是一个常见的前缀。您的修改看起来不错。
    • @Sturzgefahr--通过简单的修改就能适应你的破折号。请参阅修改后的解决方案。
    • @DarrylG——再次感谢更新的代码——完美运行,我学到了很多。该问题的说明逐字逐句地来自 NLTK 书,该书因措辞不佳的练习而臭名昭著。但是您能够编写一些可以输出我正在寻找的东西的东西,所以再次感谢。
    • @Sturzgefahr--很高兴我能帮上忙。
    【解决方案2】:

    我修改了 DarrylG 的答案(再次感谢!),方法是添加一个通过递归传递的已接受键的列表和一对 for-loops 遍历此列表以查看是否存在是可以替换的字符串开头的任何常见元素。

    编辑 11/2/19:这个修改有一个我没有注意到的错误。它会在第一次正确运行,但在随后的运行中它会替换太多字符将破折号,即:

    ----r: flesh
    ---t: cat
    ---c: stylish
    ----n: dog
    
    def insert(trie, key, value):
        """Insert into Trie"""
        if key:
            first, rest = key[0], key[1:]
            if first not in trie:
                trie[first] = {}
            insert(trie[first], rest, value)
        else:
            trie['value'] = value
    
    def display(trie, s = "", final = []):
    
        """Recursive function to Display Trie entries in alphabetical order"""
    
        for k, v in sorted(trie.items(), key = lambda x: x[0]):
    
            # dictionary sorted based upon the keys
            if isinstance(v, dict):
                display(v, s + k, final)   # s+k is extending string s for display by appending current key k
            else:
                # replace common elements at beginning of strings with dashes
                i = sum([any([f.startswith(string[:j]) for f in final]) for j in range(1, len(string))])
                string = '-' * i + s[i:]
    
                print(string + ":", v)  # not a dictionary, so print current edited s and value
                final.append(s)
    
    
    # Create Trie
    trie = {}
    insert(trie, 'chat', 'cat')
    insert(trie, 'chien', 'dog')
    insert(trie, 'chair', 'flesh')
    insert(trie, 'chic', 'stylish')
    
    #Display Use Recursive function (second argument will default to "" on call)
    display(trie)
    
    

    【讨论】:

    • 修改了我的解决方案以放置破折号。如果新解决方案更接近您的需求,请告诉我?
    猜你喜欢
    • 2013-07-24
    • 2016-05-17
    • 1970-01-01
    • 2017-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    相关资源
    最近更新 更多