Javascript 使用2次尝试自动完成多个单词的字符串

Javascript 使用2次尝试自动完成多个单词的字符串,javascript,algorithm,data-structures,Javascript,Algorithm,Data Structures,我目前正在使用1个trie进行自动完成。但是,只有当字符串的起始字符与trie的第一个字符相同时,这才有效。例如,键入santa将显示santa clara,但在输入框中键入clara时,此结果(santa clara)不会显示 如何修改代码以使用两次尝试-一次用于自动完成单词列表,另一次用于自动完成字符列表?例如,如果我在输入框中键入clara,结果santa clara仍会显示 //create node to be used to form a trie class Node { co

我目前正在使用1个trie进行自动完成。但是,只有当字符串的起始字符与trie的第一个字符相同时,这才有效。例如,键入
santa
将显示
santa clara
,但在输入框中键入
clara
时,此结果(
santa clara
)不会显示

如何修改代码以使用两次尝试-一次用于自动完成单词列表,另一次用于自动完成字符列表?例如,如果我在输入框中键入
clara
,结果
santa clara
仍会显示

//create node to be used to form a trie
class Node {
  constructor(value = '') {
    this.value = value;
    this.children = [];
  }
}

//class Trie
class Trie {
  constructor() {
    this.root = new Node();
  }

  add(value, parent = this.root) { 
    for (let i = 0, len = value.length; i < len; i++) {
      let node = parent.children.find(child => child.value[i].toLowerCase() === value[i].toLowerCase());
      if (!node) {
        node = new Node(value.slice(0, i + 1).toLowerCase()); //slice from 0 to i
        //console.log(node);
        parent.children.push(node);
      }
      parent = node;
    }
    return parent;
  }

  find(value, parent = this.root) {
    for (let i = 0, len = value.length; i < len; i++) {
      parent = parent.children.find(child => child.value[i].toLowerCase() === value[i].toLowerCase());
      if(!parent) return null;
    }
    return parent;
  }


  findWords(value, parent = this.root) {
    let top = this.find(value, parent);
    if (!top) return [];

    let words = [];

    top.children.forEach(function getWords(node) {
      if (!node.children.length) words.push(node);
      node.children.forEach(getWords);
    });

    return words;
  }

  createTrieFromArray(inputArr) {
    for (let item of inputArr) {
      let node = this.add(item);
      node.item = item;
    }
  }
}

const trie = new Trie(); 
const data = [
        "anaheim",
        "Agoura Hills",
        "Agua Dulce",
        "Aguanga",
        "Acalanes Ridge",
        "Acampo",
        "Acton",
        "Adelanto",
        "Adin",
        "san antonio",
        "san angelo",
        "san diego",
        "san jose",
        "san jacinto",
        "san francisco",
        "san bernardino",
        "san buenaventura",
        "san bruno",
        "san mateo",
        "san marcos",
        "san leandro",
        "san luis obispo",
        "san ramon",
        "san rafael",
        "san clemente",
        "san gabriel",
        "santa ana",
        "santa clarita",
        "santa clara",
        "santa cruz",
        "santa rosa",
        "santa maria",
        "santa monica",
        "santa barbara",
        "santa fe",
        "santee",
        "sandy",
        "sandy springs",
        "sanford"
      ];

trie.createTrieFromArray(data);
//console.log(trie);

const input = document.querySelector('input');
const results = document.querySelector('#results');

input.addEventListener('keyup', (e) => {

  console.log(trie);
  let resultList=''; 
  const nodes = trie.findWords(e.target.value); // << Change
  console.log(e.target.value, 'nodes ', nodes);

  if (!nodes || !nodes.length) return; // << Change

  for (let node of nodes) { // << Change
    const category = node.category ? `- ${node.category}` : '';
    let oneResult =  `<li>${node.value} ${category}</li>`;
    console.log(oneResult);
    resultList += oneResult;
  }
  results.innerHTML = resultList;

});

input.addEventListener('keydown', e => {
  // Tab Key
  if (e.keyCode === 9) {
    e.preventDefault();
    const current = trie.find(input.value);


    if (!current.children.length) return;

    input.value = current.children[0].value;
  }
});
//创建用于形成trie的节点
类节点{
构造函数(值=“”){
这个值=值;
这是:children=[];
}
}
//三类
三类{
构造函数(){
this.root=新节点();
}
add(value,parent=this.root){
for(设i=0,len=value.length;ichild.value[i].toLowerCase()==value[i].toLowerCase());
如果(!节点){
node=新节点(value.slice(0,i+1).toLowerCase());//从0到i的切片
//console.log(节点);
父.children.push(节点);
}
父节点=节点;
}
返回父母;
}
查找(值,父项=this.root){
for(设i=0,len=value.length;ichild.value[i].toLowerCase()==value[i].toLowerCase());
如果(!parent)返回null;
}
返回父母;
}
FindWord(值,父项=this.root){
让top=this.find(值,父级);
如果(!top)返回[];
让单词=[];
top.children.forEach(函数getWords(节点)){
if(!node.children.length)words.push(node);
node.children.forEach(getWords);
});
返回单词;
}
createTrieFromArray(inputArr){
for(输入端的let项){
让node=this.add(item);
node.item=项目;
}
}
}
const trie=新的trie();
常数数据=[
“阿纳海姆”,
“阿古拉山”,
“阿瓜杜尔塞”,
“阿甘加”,
“阿卡兰岭”,
“阿坎波”,
“阿克顿”,
“阿德兰托”,
“阿丁”,
“圣安东尼奥”,
“圣安杰洛”,
“圣地亚哥”,
“圣何塞”,
“圣哈辛托”,
“旧金山”,
“圣贝纳迪诺”,
“圣布埃纳文图拉”,
“圣布鲁诺”,
“圣马特奥”,
“圣马科斯”,
“圣莱安德罗”,
“圣路易斯奥比斯波”,
“圣拉蒙”,
“圣拉斐尔”,
“圣克莱门特”,
“圣加布里埃尔”,
“圣安娜”,
“圣克拉丽塔”,
“圣克拉拉”,
“圣克鲁斯”,
“圣罗莎”,
“圣玛丽亚”,
“圣莫尼卡”,
“圣巴巴拉”,
“圣达菲”,
“桑蒂”,
“桑迪”,
“沙泉”,
“桑福德”
];
createTrieFromArray(数据);
//console.log(trie);
常量输入=document.querySelector('input');
const results=document.querySelector(“#results”);
input.addEventListener('keyup',(e)=>{
console.log(trie);
让结果列表=“”;

const nodes=trie.findWords(e.target.value);//我认为您可以根据空格拆分单词,将它们添加到具有实际字符串值列表的节点的trie中。这是不够的。它需要保持父trie的顺序。例如,这两个字符串可以是“apple banana”和“banana apple”,用户正在键入“ana”两个结果都应该显示出来。首先,您需要检查单词中的字符,然后将整个单词与stringSo进行比较,就像数据库的
like%search%
一样。在这种情况下,使用
trie
对我来说似乎不是解决方案。您最好的办法是对它们进行迭代并使用
indexOf()进行检查
收集结果的方法。根据@vivek_23所说的,在构建trie时,可以包括片段(单词)。对于apple banana和banana apple,除了整个字符串本身之外,还可以插入apple和banana。每个单词的最后一个节点(分别是字母e和a)指向包含这些单词的原始字符串列表(在本例中,两个单词都指向两个字符串)。@CătălinFr–ncu是的,我想我正在尝试按照你说的做。我想我需要两次尝试:一次尝试检查一个单词,另一次尝试检查整个字符串中的每个单词。