你必须思考,如果两个字符串是你自己的产品,只要阅读它们,你会如何认识。
仅基于您提供的示例,似乎告诉两个字符串表示产品的方式是相同的,即如果较长字符串中包含较短字符串的每个单词(由空格分隔的令牌)。
您可能还想忽略大小写。
像这样的东西应该的基本用法工作:
const tokens = s => s.toLowerCase().split(/\s+/g);
const sameProducts = (s1, s2) => {
const s1Tokens = tokens(s1);
const s2Tokens = tokens(s2);
const [shorterTokens, longerTokens] = s1Tokens.length > s2Tokens.length
? [s2Tokens, s1Tokens]
: [s1Tokens, s2Tokens];
return shorterTokens.every(st => longerTokens.includes(st));
}
console.log(
sameProducts(
'Canon 50mm f/1.2L',
'Canon EF 50mm f/1.2L USM Lens'
)
)
此代码将有二次的时间复杂度,因为最昂贵的操作是指,相对于短串在每一个令牌,你必须迭代长字符串中的每个标记。
一个简单的优化就是从较长的字符串中构建一个Set<token>
。这将使操作线性化,因为搜索一个集合是O(1)
。
const tokens = s => s.toLowerCase().split(/\s+/g);
const sameProducts = (s1, s2) => {
const s1Tokens = tokens(s1);
const s2Tokens = tokens(s2);
const [shorterTokens, longerTokens] = s1Tokens.length > s2Tokens.length
? [s2Tokens, s1Tokens]
: [s1Tokens, s2Tokens];
const longerTokensSet = longerTokens.reduce((s, t) => {
s.add(t);
return s;
}, new Set());
return shorterTokens.every(st => longerTokensSet.has(st));
}
console.log(
sameProducts(
'Canon 50mm f/1.2L',
'Canon EF 50mm f/1.2L USM Lens'
)
)
现在你必须要考虑,做所有令牌必须匹配?也许只有与品牌和焦距对应的令牌才能匹配。
如果是这样的话,你可能还需要验证两个字符串在分析它们并立即返回false
如果产品均被认为是无效。
这里有一个粗略的想法:
const productSet = new Set(['canon'])
const focalLengthsSet = new Set(['50mm']);
const isMeaningful = t => productSet.has(t) || focalLengthsSet.has(t);
const meaningfulTokens = s => s.toLowerCase().split(/\s+/g).filter(isMeaningful);
const validTokens = (tokens, s) => {
const valid = tokens.length === 2; // <-- could do better validation here
console.assert(valid, `Missing token(s) in ${s}`);
return valid;
}
const sameProducts = (s1, s2) => {
const s1Tokens = meaningfulTokens(s1);
if (!validTokens(s1Tokens, s1)) { return false; }
const s2Tokens = meaningfulTokens(s2);
if (!validTokens(s2Tokens, s2)) { return false; }
const [shorterTokens, longerTokens] = s1Tokens.length > s2Tokens.length
? [s2Tokens, s1Tokens]
: [s1Tokens, s2Tokens];
const longerTokensSet = longerTokens.reduce((s, t) => {
s.add(t);
return s;
}, new Set());
return shorterTokens.every(st => longerTokensSet.has(st));
}
console.log(
sameProducts(
'Canon 50mm f/1.3',
'Canon EF 50mm f/1.2'
)
)
console.log(
sameProducts(
'Canon 50mm f/1.3',
'Canon EF f/1.2' // <-- missing focal length
)
)
现在你可以考虑不每个焦距对应于每一个产品或者是更具体产品?
做令牌包含明确依赖于先前匹配的令牌逻辑是什么?
以上所有的都只是基本方法和技巧,你可以使用,但实际的解决方案将在很大程度上取决于你的具体情况而定。
测量字符串相似性的常用算法叫做Levenstein distance。
两个单词之间的Levenshtein距离是单字符的最小数目编辑改变一个字到其他需要的(插入,缺失或取代)。
该算法将允许您将字符串直接,也许匹配,如果你编辑距离阈值是不够严谨(虽然这可能提供假阳性)或通过确保比较单独的标记时,你甚至可以占到拼错的产品来说吧它们处于彼此特定的编辑距离内。
定义 '相似' – Serge
你需要如何分类定义*“相似”*字符串,以及如何相似足够相似。你们都需要说明其他的变化。没有具体的问题,这是一个非常困难的问题,因为要求机器学习方法具有100%的准确性。 –
这不是一个微不足道的问题。即使根据你的例子,目前还不清楚你是否意味着这两者都是同等产品。 –