English 中文(简体)
自动完整样式前缀查找
原标题:Autocomplete Style Prefix Lookup

举一个具体例子:

  • You have a list of every first name in the USA.
  • You want to autosuggest completions in a GUI.

显而易见的是, 使用一个 radex 树来获取给定前缀的名称列表。 但是, 这并没有考虑到频率信息 。 因此, 与其仅仅使用前5个结果, 不如首先使用最常用的 5 个 名称 :

例如,对于前缀 < code>dan ,

 (5913,  Daniel )
 (889,  Danny )
 (820,  Dana )
 (272,  Dan )
 (60,  Dane )

是否我错过了三角树算法? 当然,理想的实施(如果存在的话)在我脑海中的是俾硫酮。

<强度>UPDATE: 一般对Paddy3113的提议感到满意,不过我会说,当我喂给它2.6GB文件时,它会完全爆炸,而这正是我正在减少的文件之一。

samz;Samzetta|Samzara|Samzie
samza;Samzara
samzar;Samzara
samzara;Samzara
samze;Samzetta
samzet;Samzetta
samzett;Samzetta
samzetta;Samzetta
samzi;Samzie
samzie;Samzie

# Format - PREFIX;"|".join(CHOICES).

我们还有几天时间来讨论赏金问题,所以我仍在寻找杀手的解决方案。因为这不仅仅是减少问题,而且也是看事物的外观问题。

最佳回答

是的, 我们可以使用三角节点。 三角节点最常见的名称是 (1) 三角节点的名称 或 (2) 三角节点的孩子最常使用的名称 。 这里使用一些 Python 代码 。

from collections import defaultdict


class trie:
    __slots__ = ( children ,  freq ,  name ,  top5 )

    def __init__(self):
        self.children = defaultdict(trie)
        self.freq = 0
        self.name = None
        self.top5 = []

    def __getitem__(self, suffix):
        node = self
        for letter in suffix:
            node = node.children[letter]
        return node

    def computetop5(self):
        candidates = []
        for letter, child in self.children.items():
            child.computetop5()
            candidates.extend(child.top5)
        if self.name is not None:
            candidates.append((self.freq, self.name))
        candidates.sort(reverse=True)
        self.top5 = candidates[:5]

    def insert(self, freq, name):
        node = self[name]
        node.freq += freq
        node.name = name


root = trie()
with open( letter_s.txt ) as f:
    for line in f:
        freq, name = line.split(None, 1)
        root.insert(int(freq.strip()), name.strip())
root.computetop5()
print(root[ St ].top5)
问题回答

在不知道调音的情况下,我首先假设我有一个名称及其频率的清单,然后用该前缀构建一套名称的字典绘图前缀,然后将每组名称转成仅是前5个w.r.t.频率的列表。

使用来自的男孩名字列表,这些男孩的名字来自http://www.ons.gov.uk/ons/publications/re-re-reference-tables.html?edimation=tcm:77-243746" rel=“nofollow”>这里的“nofol”按摩,以创建一个https://docs.google.com/open?id=0Bw2-lCRSFikqdnlhYng4OXR6Zzg" rel=“nofollow” > text file ,其中每条线都是事件的整数频率,有些空格,然后有一个像这样的名字:

8427    OLIVER 
7031    JACK 
6862    HARRY 
5478    ALFIE 
5410    CHARLIE 
5307    THOMAS 
5256    WILLIAM 
5217    JOSHUA 
4542    GEORGE 
4351    JAMES 
4330    DANIEL 
4308    JACOB 
...

以下代码构建了字典:

from collections import defaultdict

MAX_SUGGEST = 5

def gen_autosuggest(name_freq_file_name):
    with open(name_freq_file_name) as f:
        name2freq = {}
        for nf in f:
            freq, name = nf.split()
            if name not in name2freq:
                name2freq[name] = int(freq)
    pre2suggest = defaultdict(list)
    for name, freq in sorted(name2freq.items(), key=lambda x: -x[1]):
        # in decreasing order of popularity
        for i, _ in enumerate(name, 1):
            prefix = name[:i]
            pre2suggest[prefix].append((name, name2freq[name]))
    # set max suggestions
    return {pre:namefs[:MAX_SUGGEST]
            for pre, namefs in pre2suggest.items()}

if __name__ ==  __main__ :
    pre2suggest = gen_autosuggest( 2010boysnames_popularity_engwales2.txt )

如果您给出了前缀, 则会回复您的建议( 连同此情况下的频率, 但如有需要, 可以丢弃 :

>>> len(pre2suggest)
15303
>>> pre2suggest[ OL ]
[( OLIVER , 8427), ( OLLIE , 1130), ( OLLY , 556), ( OLIVIER , 175), ( OLIWIER , 103)]
>>> pre2suggest[ OLI ]
[( OLIVER , 8427), ( OLIVIER , 175), ( OLIWIER , 103), ( OLI , 23), ( OLIVER-JAMES , 16)]
>>> 

查看没有尝试 :-)

< 强力 > 时间杀手 < /强 >

如果运行需要很长的时间, 那么您可能会预先计算dict, 并将其保存到文件, 然后在需要使用泡菜模块时装入预计算值 :

>>> import pickle
>>> 
>>> savename =  pre2suggest.pcl 
>>> with open(savename,  wb ) as f:
    pickle.dump(pre2suggest, f)


>>> # restore it
>>> with open(savename,  rb ) as f:
    p2s = pickle.load(f)


>>> p2s == pre2suggest
True
>>> 

你基本上可以增加一个三角执行, 以存储它的受欢迎儿童, 而不是按字母顺序排列, 上面说,你还要在三角的每个节点 存储受欢迎儿童。

如何做到这一点的想法如下:

构造字符串三角并存储树上每个节点的整数。 此节点表示使用该节点的名称数量。 所以当该名称插入三角点时, 您会加增该名称的所有节点 。

然后您就可以通过贪婪地选择具有最高值的名称来决定顶级名称。

在形式上,它与任何弦三角构造算法一样,但加一步加一整数。

如果您想要快速查看, 唯一的真正解决办法是预算任何给定前缀的答案。 如果数据没有改变, 则此选项很好, 但是您需要一种方法来保持您的负载时间小化 。

我建议使用 DBM 存储预编字典。 这基本上是一个字典, 内容存储在磁盘上, 并查找您参考的条目 。 见 < a href=" http://docs. python.org/library/ anidbm.html" rel=“ nofollow” > http://docs. python.org/library/ anidbm.html 。 唯一的下边是值必须是字符串, 所以您需要存储前5个条目的逗号分隔列表, 例如, 并在查找时将其分割 。

这将比泡菜有更快的开始时间, 因为 DB 不需要加载。 它也比使用 Sqlite 简单得多 。





相关问题
How to add/merge several Big O s into one

If I have an algorithm which is comprised of (let s say) three sub-algorithms, all with different O() characteristics, e.g.: algorithm A: O(n) algorithm B: O(log(n)) algorithm C: O(n log(n)) How do ...

Grokking Timsort

There s a (relatively) new sort on the block called Timsort. It s been used as Python s list.sort, and is now going to be the new Array.sort in Java 7. There s some documentation and a tiny Wikipedia ...

Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Enumerating All Minimal Directed Cycles Of A Directed Graph

I have a directed graph and my problem is to enumerate all the minimal (cycles that cannot be constructed as the union of other cycles) directed cycles of this graph. This is different from what the ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签