如何阅读此基数树结构以确定下一个字符串概率
How can I read this Radix Tree structure to determine next-string probability?
在JavaScript中,我试图接受给定的用户输入并猜测3个最有可能完成用户当前(不完整(输入的单词的单词。猜测基于用户过去的输入。我正在这里,在这个JSFiddle中研究这个。
我为记录用户过去的输入而构建的结构是修改后的基数树(又名Patricia Trie(:
输入:"hey
">
{
"h": {
"value": "h",
"count": 1,
"followables": {
"e": {
"value": "e",
"count": 1,
"followables": {
"y": {
"value": "y",
"count": 1,
"followables": {}
}
}
}
}
}
}
这个数据结构是完美构建的,我认为它是实现所述目标的最佳结构。我的问题是读取基数树数据以定义给定输入的 3 个最可能的单词的功能。例如,在上面的数据中,如果用户输入" h
",猜测函数应该返回如下对象:
guess : {
1 : "hey",
2 : "",
3 : ""
}
所以这是我的代码/进度:
学习 - 获取完成的输入字符串并将组合组织到基数树中 ( brain
(:
function learn(message, brain) {
if (message.length == 0) return {}; // or do something else
var ch = message[0]; // get the first character
if (!brain[ch]) { // create new node when not exists
brain[ch] = {
value: ch,
count: 1,
followables: {}
};
} else { // increment count when exist
brain[ch].count += 1;
}
var substr = message.substring(1); // remove first character
if (substr) { // do it for the remaining substring
brain[ch].followables = learn(substr, brain[ch].followables);
} else {
renderData();
}
return brain;
}
这一切都做对了。不幸的是,下一个代码,旨在读取数据并猜测用户正在键入的单词,并不好。我对一个对我来说非常复杂的功能有问题。我把它分成了几个小函数,因为我已经知道这是最佳实践,但恐怕我弄得一团糟,可能更简单:
猜测 - 获取"学习"的字符串数据,并猜测用户可能正在键入哪个单词:
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;
}
}
旁注 - 虽然在字典上进行模糊字符串搜索是一种更常见的方法,但学习方法是根据用户的写作/消息传递风格定制猜测并支持用户非标准词汇("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(对我来说并不有趣。重点是递归函数,这些函数深入挖掘树内部以获取建议。这个得到给定单词的最终followables
:
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;
};
};
}
您可以在此小提琴中看到详细信息,我不得不删除您的一些代码。在任何地方集成都很容易,例如您可以设置其他建议字段,当前为:
guesses: [
{
element: $('#guess-1'),
word: ''
},
{
element: $('#guess-2'),
word: ''
},
{
element: $('#guess-3'),
word: ''
}
]
编辑:修复了在右侧添加字母的错误。
- 滚动到容器中的下一个元素-几乎到了
- 替换字符串的下一个匹配项
- Visual Studio 2010跳转到下一个任意字符/字符串
- 我该如何编写一个正则表达式来匹配字符串后面的值(到下一个逗号)
- 如何阅读此基数树结构以确定下一个字符串概率
- 如何在切片后的下一个“:”之后获取子字符串
- 正则表达式,用于查找字符串的所有出现项,然后查找其后面的下一个空格
- 获取从第一个字符到下一个空格的字符串的一部分
- Javascript 中的第一个下一个/上一个子字符串位置
- 字符串-元音到大写,字母到下一个字母-Javascript
- JavaScript如何在忽略ANSI代码的情况下每隔n个字符拆分一个字符串
- 将字符串中的字母替换为下一个字母,并将更改后的字符串中的元音大写
- 我想分割一个字符串,然后放到下拉列表中
- 如何获得下一个兄弟的值,如果元素搜索特定的字符串
- 如何检查下一个存在的字符串中的字符在javascript
- 使用javascript将字母更改为HTML字符串中的下一个元素
- 在Javascript中递增一个字符串下标数字
- 将字符串从一个函数传递到下一个javascript函数
- 如何在不使用indexOf的情况下匹配另一个字符串中的字符串
- 不能调用下划线.字符串函数' lpad '用于错误'未捕获的类型错误:_.Lpad不是一个函数