Javascript 如何读取这个基数树结构来确定下一个字符串的概率?
在JavaScript中,我尝试接受给定的用户输入,并猜测可能完成用户当前(不完整)键入的单词的3个最可能的单词。猜测基于用户过去的输入。我正在做这个 我构建的用于记录用户过去输入的结构是经过修改的: 输入:“Javascript 如何读取这个基数树结构来确定下一个字符串的概率?,javascript,patricia-trie,Javascript,Patricia Trie,在JavaScript中,我尝试接受给定的用户输入,并猜测可能完成用户当前(不完整)键入的单词的3个最可能的单词。猜测基于用户过去的输入。我正在做这个 我构建的用于记录用户过去输入的结构是经过修改的: 输入:“嘿” 这个数据结构构建得非常完美,我认为它是实现上述目标的最佳结构。我的问题是读取基数树数据以定义给定输入的3个最可能的单词的函数。例如,在上述数据中,如果用户输入“h”,猜测函数应返回如下对象: guess : { 1 : "hey", 2 : "", 3 : "" }
嘿
”
这个数据结构构建得非常完美,我认为它是实现上述目标的最佳结构。我的问题是读取基数树数据以定义给定输入的3个最可能的单词的函数。例如,在上述数据中,如果用户输入“h
”,猜测函数应返回如下对象:
guess : {
1 : "hey",
2 : "",
3 : ""
}
下面是我的代码/进度:
学习-获取完成的输入字符串,并将组合组织到基数树中(brain
):
没关系。不幸的是,下一个用于读取数据并猜测用户正在键入的单词的代码并不好。对我来说,这是一个非常复杂的函数。我把它分成了几个小函数,据我所知,这是最好的做法,但我担心我弄糟了,可能会简单得多:
猜测-获取“习得”字符串数据,并对用户可能键入的单词进行3次猜测:
function guess(progress, brain) {
console.log("Guessing based on: " + progress);
var guesses = {
0: "",
1: "",
2: ""
}
var firstChar = progress[0];
if (brain[firstChar]) {
var step = brain[firstChar];
for (var i = 0; i < progress.length; i++) {
var char = progress[i];
if (step.followables[char]) {
step = step.followables[char];
if (i == progress.length) {
var guesses = nextStrings(step.followables);
renderGuesses(guesses);
}
} else {
renderGuesses(guesses);
}
}
} else {
renderGuesses(guesses);
}
}
function renderGuesses(guesses) {
console.log(guesses);
$('#guess-1').text(guesses[0]);
$('#guess-2').text(guesses[1]);
$('#guess-3').text(guesses[2]);
}
function nextStrings(followables) {
console.log('Searching for next string...');
var results;
if (followables.length > 0) {
results = chooseRoutes(followables);
} else {
results = {
0: "",
1: "",
2: ""
}
}
console.log(result);
return result;
}
function chooseRoutes(followables) {
var results = {
0: {
value: "",
count: 0
},
1: {
value: "",
count: 0
},
2: {
value: "",
count: 0
}
};
for (var i = 0; i < followables.length; i++) {
var count = followables[i].count;
if (count > results[0].count) {
results[0].value = followStr(followables[i], "");
} else if (count > results[1].count) {
results[1].value = followStr(followables[i], "");
} else if (count > results[2].count) {
results[2].value = followStr(followables[i], "");
}
}
console.log(results);
return results;
}
function followStr(followables, str) {
var guess = {
value: "",
count: 0
};
for (var i = 0; i < followables.length; i++) {
if (followables[i].count > guess.count) {
guess = followables[i];
}
}
followables = guess.followables;
if (guess.value != " ") {
str += guess;
followStr(followables, str);
} else {
console.log(str);
return str;
}
}
功能猜测(进展,大脑){
log(“基于:+进度的猜测”);
var猜测={
0: "",
1: "",
2: ""
}
var firstChar=progress[0];
if(brain[firstChar]){
var step=大脑[firstChar];
对于(变量i=0;i0){
结果=选择结果(如下表);
}否则{
结果={
0: "",
1: "",
2: ""
}
}
控制台日志(结果);
返回结果;
}
函数选择器输出(以下选项){
风险值结果={
0: {
值:“”,
计数:0
},
1: {
值:“”,
计数:0
},
2: {
值:“”,
计数:0
}
};
for(var i=0;i结果[0]。计数){
结果[0].value=followStr(followstables[i],“”);
}else if(计数>结果[1]。计数){
结果[1],值=followStr(followstables[i],“”);
}否则如果(计数>结果[2]。计数){
结果[2],值=followStr(followstables[i],“”);
}
}
控制台日志(结果);
返回结果;
}
函数followStr(followsables,str){
var猜测={
值:“”,
计数:0
};
for(var i=0;iguess.count){
猜测=可遵循的;
}
}
followables=guess.followables;
如果(guess.value!=“”){
str+=猜测;
followStr(followstables,str);
}否则{
console.log(str);
返回str;
}
}
侧注-虽然在字典上进行模糊字符串搜索是一种更常见的方法,但学习方法是一种根据用户的写作/消息传递风格定制猜测并支持用户非标准词汇表的好方法(“
heyy
”、“sup
”、“:p
”、“lol
”)-这些猜测的结果可以与标准词典结果相结合(并优先于标准词典结果)。用于词典的结构不正确,它应该包含对象数组。例如,输入以下文字后:
hi
hi
hi
hi
hi
hey
hello
hella
结构应为:
history: [{
letter: "h",
count: 8,
followables: [{
letter: "e",
count: 3,
followables: [{
letter: "y",
count: 1,
followables: []
}, {
letter: "l",
count: 2,
followables: [{
letter: "l",
count: 2,
followables: [{
letter: "o",
count: 1,
followables: []
}, {
letter: "a",
count: 1,
followables: []
}]
}]
}]
}, {
letter: "i",
count: 5,
followables: []
}]
}]
您创建和存储历史记录的方式(我将使用localStorage)对我不感兴趣。重点放在递归函数上,这些函数深入到树的内部以获取建议。这一个获得给定单词的最终可遵循项
:
findChildren: function (node, depth) {
/* Traverse history for current word, there is only one path */
for (k in node) {
if (node[k].letter == app.progress[depth]) {
if (depth + 1 == app.progress.length) {
/* Found it, hope it has followables */
return node[k].followables;
} else {
/* Must go deeper... */
return app.findChildren(node[k].followables, depth + 1);
};
};
};
/* No results */
return false;
}
第二个(getWord)创建建议:
countWordsFromNode: function (node) {
for (i in node) {
if (node[i].followables.length) {
app.countWordsFromNode(node[i].followables);
} else {
app.totalInNode++;
};
};
},
getWord: function (node, limit) {
/* First sort by count */
var sorted = node.sort(function (n1, n2) {
return n2.count - n1.count;
});
for (k in sorted) {
app.guesses[app.totalFound].word += sorted[k].letter;
if (sorted[k].followables.length) {
app.totalInNode = 0;
app.countWordsFromNode(sorted[k].followables);
for (m = 1; m < app.totalInNode; m++) {
if ((app.totalFound + m) < limit) {
app.guesses[app.totalFound + m].word += sorted[k].letter;
};
};
app.getWord(sorted[k].followables, limit);
} else {
/* End of word */
app.totalFound++;
};
if (app.totalFound >= limit) {
/* Found all suggestions */
break;
};
};
}
编辑:
修正了在右边添加字母的错误。抛开主观因素不谈,实际上我对自己无法构建这个
guess
函数感到有点沮丧。功能/总体目标实际是高级/困难的,还是我需要更多的练习?在过去的2-3年的高中生活中,我一直在学习JS,我很想知道现在我是否能够轻松地完成类似的事情……这不是一个特别容易实现的算法,但看看你可能会发现,如果你有一个匹配的单词数据库,那么你可能会发现它更容易实现。@Qantas949当然,我可能希望在生产实现中结合使用基于字典的典型模糊字符串搜索。我在这里的目的是关注用户的输入,它擅长猜测常见但不正确的字符串,如“u”、“:P”,“嗯,您的示例树不是实际的trie,它不是压缩的?那.count
到底代表了什么?@Bergi也许不是-我没有太多地研究trie背后的基本思想,但它的结构像一个,遵循相同的思想,减去,也许,你所说的压缩。和计数
表示
findChildren: function (node, depth) {
/* Traverse history for current word, there is only one path */
for (k in node) {
if (node[k].letter == app.progress[depth]) {
if (depth + 1 == app.progress.length) {
/* Found it, hope it has followables */
return node[k].followables;
} else {
/* Must go deeper... */
return app.findChildren(node[k].followables, depth + 1);
};
};
};
/* No results */
return false;
}
countWordsFromNode: function (node) {
for (i in node) {
if (node[i].followables.length) {
app.countWordsFromNode(node[i].followables);
} else {
app.totalInNode++;
};
};
},
getWord: function (node, limit) {
/* First sort by count */
var sorted = node.sort(function (n1, n2) {
return n2.count - n1.count;
});
for (k in sorted) {
app.guesses[app.totalFound].word += sorted[k].letter;
if (sorted[k].followables.length) {
app.totalInNode = 0;
app.countWordsFromNode(sorted[k].followables);
for (m = 1; m < app.totalInNode; m++) {
if ((app.totalFound + m) < limit) {
app.guesses[app.totalFound + m].word += sorted[k].letter;
};
};
app.getWord(sorted[k].followables, limit);
} else {
/* End of word */
app.totalFound++;
};
if (app.totalFound >= limit) {
/* Found all suggestions */
break;
};
};
}
guesses: [
{
element: $('#guess-1'),
word: ''
},
{
element: $('#guess-2'),
word: ''
},
{
element: $('#guess-3'),
word: ''
}
]