JS - 是否有更有效的方法将数组中的值与目标搜索词进行比较
JS - Is there a more efficient way to compare values in an array to a target search term
我的目标是在一组 object 中搜索标题相似或与搜索词完全匹配的内容。问题是我想优先考虑完全匹配而不是仅包含字符串的匹配。
当前代码通过多次循环来做到这一点,每次使用不同的条件,returns object 如果匹配。
class Item {
constructor(title) {
this.title = title;
}
}
function findMatch(term) {
const items = [new Item("term"), new Item("Longer Term"), new Item("Completely Different Title")];
// Check if any match the search term exactly
for (var item of items) {
if (item.title === term) return item;
}
// Check if any match the search term, ignoring case
for (var item of items) {
if (item.title.toLowerCase() === term.toLowerCase()) return item;
}
// Check if any start with the search term
for (var item of items) {
if (item.title.toLowerCase().startsWith(term.toLowerCase())) return item;
}
// Check if any end with the search term
for (var item of items) {
if (item.title.toLowerCase().endsWith(term.toLowerCase())) return item;
}
// Check if any contain the search term
for (var item of items) {
if (item.title.toLowerCase().includes(term.toLowerCase())) return item;
}
return null;
}
console.log(findMatch("different")); // Item with title "Completely Different Title"
有没有一种方法可以更有效地执行此操作,例如在一个循环中 - 或者有没有更好的方法来搜索字符串?
我研究过使用 Levenshtein 算法,但这不适用于搜索“Comp”并获得标题为“Completely Different Title”的项目,因为“Comp”和“Completely Different Title”之间有很多不同之处" 比 "Comp" 和 "term" 之间的距离要小 - 有没有办法将相同的想法纳入此搜索?
如果您正在寻找 效率,我能想到的唯一可以减少处理的改进是提前将字符串小写,而不是将每个字符串中的每个值都小写环形。不过,这可能是一个非常微小的改进,在大多数情况下是不明显的。
class Item {
constructor(title) {
this.title = title;
this.lowerTitle = title.toLowerCase();
}
}
function findMatch(term) {
const lowerTerm = term.toLowerCase();
// use item.lowerTitle and lowerTerm when appropriate
您要实现的逻辑从根本上需要对所有元素进行循环以寻找一个条件,然后对所有元素进行另一个循环以寻找另一个条件,等等。因此没有真正的方法可以提高当前实现的计算复杂性.
您可以将部分或全部条件与正则表达式结合起来,但这会破坏要 returned 的匹配类型的优先顺序。
如果您想使代码 更短 并且更易于维护,这很简单 - 您可以使用一组回调,按顺序为每个项目调用:
const comparers = [
(a, b) => a === b,
(a, b) => a.startsWith(b),
(a, b) => a.endsWith(b),
(a, b) => a.includes(b),
]
for (const fn of comparers) {
if (fn(item.lowerTitle, lowerTerm)) return item;
}
Is there a way to incorporate the same idea into this search?
检查 Levenshtein 距离会有点不同。您需要无条件地循环所有项目,并在循环完成后 return 找到最佳匹配项,而不是循环项目并 return 匹配一个项目。
let bestItem;
let lowestDistance = Infinity;
for (const item of items) {
const dist = compare(item.lowerTitle, lowerTerm);
if (dist < lowestDistance) {
bestItem = item;
lowestDistance = dist;
}
}
return bestItem;
你至少会而不是最后.includes
检查。根据您想要的逻辑,您也可以删除 startsWith
和 endsWith
检查作为交换。
您可以根据“相似性”为您的项目分配 score
,然后根据该分数和 return 匹配项过滤和排序项目:
class Item {
constructor(title) {
this.title = title;
}
}
const items = [new Item("term"), new Item("Longer Term"), new Item("Completely Different Title")];
function findMatch(term) {
for (var item of items) {
// Check if any match the search term exactly
if (item.title === term) item.score = 10000;
// Check if any match the search term, ignoring case
else if (item.title.toLowerCase() === term.toLowerCase()) item.score = 1000;
// Check if any start with the search term
else if (item.title.toLowerCase().startsWith(term.toLowerCase())) item.score = 100;
// Check if any end with the search term
else if (item.title.toLowerCase().endsWith(term.toLowerCase())) item.score = 10;
// Check if any contain the search term
else if (item.title.toLowerCase().includes(term.toLowerCase())) item.score = 1;
}
return items.filter(i => 0 < i.score).sort((a, b) => b.score - a.score).map(i => delete i.score && i)
}
console.log(findMatch("different")); // Item with title "Completely Different Title"
console.log(findMatch("term"));
我的目标是在一组 object 中搜索标题相似或与搜索词完全匹配的内容。问题是我想优先考虑完全匹配而不是仅包含字符串的匹配。
当前代码通过多次循环来做到这一点,每次使用不同的条件,returns object 如果匹配。
class Item {
constructor(title) {
this.title = title;
}
}
function findMatch(term) {
const items = [new Item("term"), new Item("Longer Term"), new Item("Completely Different Title")];
// Check if any match the search term exactly
for (var item of items) {
if (item.title === term) return item;
}
// Check if any match the search term, ignoring case
for (var item of items) {
if (item.title.toLowerCase() === term.toLowerCase()) return item;
}
// Check if any start with the search term
for (var item of items) {
if (item.title.toLowerCase().startsWith(term.toLowerCase())) return item;
}
// Check if any end with the search term
for (var item of items) {
if (item.title.toLowerCase().endsWith(term.toLowerCase())) return item;
}
// Check if any contain the search term
for (var item of items) {
if (item.title.toLowerCase().includes(term.toLowerCase())) return item;
}
return null;
}
console.log(findMatch("different")); // Item with title "Completely Different Title"
有没有一种方法可以更有效地执行此操作,例如在一个循环中 - 或者有没有更好的方法来搜索字符串?
我研究过使用 Levenshtein 算法,但这不适用于搜索“Comp”并获得标题为“Completely Different Title”的项目,因为“Comp”和“Completely Different Title”之间有很多不同之处" 比 "Comp" 和 "term" 之间的距离要小 - 有没有办法将相同的想法纳入此搜索?
如果您正在寻找 效率,我能想到的唯一可以减少处理的改进是提前将字符串小写,而不是将每个字符串中的每个值都小写环形。不过,这可能是一个非常微小的改进,在大多数情况下是不明显的。
class Item {
constructor(title) {
this.title = title;
this.lowerTitle = title.toLowerCase();
}
}
function findMatch(term) {
const lowerTerm = term.toLowerCase();
// use item.lowerTitle and lowerTerm when appropriate
您要实现的逻辑从根本上需要对所有元素进行循环以寻找一个条件,然后对所有元素进行另一个循环以寻找另一个条件,等等。因此没有真正的方法可以提高当前实现的计算复杂性.
您可以将部分或全部条件与正则表达式结合起来,但这会破坏要 returned 的匹配类型的优先顺序。
如果您想使代码 更短 并且更易于维护,这很简单 - 您可以使用一组回调,按顺序为每个项目调用:
const comparers = [
(a, b) => a === b,
(a, b) => a.startsWith(b),
(a, b) => a.endsWith(b),
(a, b) => a.includes(b),
]
for (const fn of comparers) {
if (fn(item.lowerTitle, lowerTerm)) return item;
}
Is there a way to incorporate the same idea into this search?
检查 Levenshtein 距离会有点不同。您需要无条件地循环所有项目,并在循环完成后 return 找到最佳匹配项,而不是循环项目并 return 匹配一个项目。
let bestItem;
let lowestDistance = Infinity;
for (const item of items) {
const dist = compare(item.lowerTitle, lowerTerm);
if (dist < lowestDistance) {
bestItem = item;
lowestDistance = dist;
}
}
return bestItem;
你至少会而不是最后.includes
检查。根据您想要的逻辑,您也可以删除 startsWith
和 endsWith
检查作为交换。
您可以根据“相似性”为您的项目分配 score
,然后根据该分数和 return 匹配项过滤和排序项目:
class Item {
constructor(title) {
this.title = title;
}
}
const items = [new Item("term"), new Item("Longer Term"), new Item("Completely Different Title")];
function findMatch(term) {
for (var item of items) {
// Check if any match the search term exactly
if (item.title === term) item.score = 10000;
// Check if any match the search term, ignoring case
else if (item.title.toLowerCase() === term.toLowerCase()) item.score = 1000;
// Check if any start with the search term
else if (item.title.toLowerCase().startsWith(term.toLowerCase())) item.score = 100;
// Check if any end with the search term
else if (item.title.toLowerCase().endsWith(term.toLowerCase())) item.score = 10;
// Check if any contain the search term
else if (item.title.toLowerCase().includes(term.toLowerCase())) item.score = 1;
}
return items.filter(i => 0 < i.score).sort((a, b) => b.score - a.score).map(i => delete i.score && i)
}
console.log(findMatch("different")); // Item with title "Completely Different Title"
console.log(findMatch("term"));