如果以下代表我的数组,
1 UserA | Bob Smith | 12345 | hello
2 UserA | Bob Smith | 12345 |
3 UserA | Bob Smith | 123 |
4 UserA | Bob Smith
5 UserB | Bob Smith | 12333 | hello
我将以下对象与:
进行比较UserA | Bob Smith | 2222
我喜欢"最匹配"在我的用户阵列上的第4行。
UserA | Bob Smith | 2222 | hello
也与第4行匹配。
我能做些什么来获得最佳匹配?
我可以循环并做一个if-else,但这似乎很脏,希望有人有一个聪明的解决方案。
我目前的做法:
尝试匹配
UserA | Bob Smith | 2222 | hello
它什么也没有返回,所以切掉最后一个并再试一次
UserA | Bob Smith | 2222
它什么也没有返回,所以切掉最后一个并再试一次
UserA | Bob Smith
匹配第4行,返回true!思考??
其他信息:
[
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234, "output": "hello"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234},
{"Title": "UserA", "Name": "Bob Smith", "Number": 123},
{"Title": "UserA", "Name": "Bob Smith"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 12333, "output": "hello"}
]
它们都包含标题,名称,编号。有些可能包含或不包含其他信息,例如"输出"
我想要的对象
{"Title": "UserA", "Name": "Bob Smith", "Number": 122, "output": "hello"}
将与第4个数组对象匹配,因为它从左到右匹配,这是"最佳匹配"
答案 0 :(得分:1)
您可以尝试映射一个函数,该函数返回数组中每个项目的分数,然后获得分数最高的索引,而不是每次都循环播放?
var arr = [
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234, "output": "hello"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234},
{"Title": "UserA", "Name": "Bob Smith", "Number": 123},
{"Title": "UserA", "Name": "Bob Smith"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 12333, "output": "hello"}
];
var target = {"Title": "UserA", "Name": "Bob Smith", "Number": 122, "output": "hello"};
var highest = 0;
var index = undefined;
function score(obj, el, i) {
var s = 0;
Object.keys(obj).forEach(key => s += el[key] === obj[key] ? 1 : 0);
if (s > highest) {
highest = s;
index = i;
}
}
arr.forEach((el, i) => score(target, el, i));
这应该留下最高等于最高分数和索引等于数组中该项目的索引。
答案 1 :(得分:1)
我的看法
/**
@func bestMatch - returns best matching object
@desc This function takes an array of objects (haystack) and compares
each property of needle to the property of haystack[n].
haystack[n] gets a "score" based on how many properties exist and
match the properties of needle, and js custom sort method is
used, based off the score, so that the first element in the
sorted haystack should have the highest score and therefore
"win" and be the best match
@param1 Array of objects to match against (haystack)
@param2 Object to find matches for (needle)
@return Object from haystack that is closest match against needle
**/
function bestMatch(h,n) {
return h.sort(function(a,b){
var c=0,d=0,p;
for (p in n) {
if (n.hasOwnProperty(p)) {
c+=Number((a[p]||0)&&a[p]===n[p]);
d+=Number((b[p]||0)&&b[p]===n[p]);
}
}
return (d<c)?-1:1;return 0;
})[0];
}
示例强>
var data = [
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234, "output": "hello"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234},
{"Title": "UserA", "Name": "Bob Smith", "Number": 123},
{"Title": "UserA", "Name": "Bob Smith", "Number": 12333, "output": "hello"},
{"Title": "UserA", "Name": "Bob Smith"}
];
var input= {"Title": "UserA", "Name": "Bob Smith", "Number": 12333};
bestMatch(data,input);
// return: {"Title":"UserA","Name":"Bob Smith","Number":12333,"output":"hello"}
答案 2 :(得分:0)
线性搜索:
<script>
function FindBestMatch( a, item )
{
var bestIndex = null;
var bestNumMatch = -1;
var bestNumMismatch = 0;
var numItemElements = item.length;
for (var i in a)
{
for (var numMatch=0; numMatch<numItemElements; numMatch++)
{
if (a[i][numMatch]!=item[numMatch]) break;
}
var numMismatch = a[i].length - numMatch;
if (numMatch==numItemElements && !numMismatch) return i;
if (numMatch>bestNumMatch
|| (numMatch==bestNumMatch && numMismatch<bestNumMismatch))
{
bestIndex = i;
bestNumMatch = numMatch;
bestNumMismatch = numMismatch;
}
}
return bestIndex;
}
var myArray = [
[ 'UserA', 'Bob Smith', 12345, 'hello' ],
[ 'UserA', 'Bob Smith', 12345 ],
[ 'UserA', 'Bob Smith', 123 ],
[ 'UserA', 'Bob Smith' ],
[ 'UserA', 'Bob Smith', 12345, 'hello' ]
];
var someItem = [ 'UserA', 'Bob Smith', 2222 ];
var i = FindBestMatch(myArray,someItem);
alert("The best match is number "+i+":\n\n"+myArray[i].join(" | "));
</script>
答案 3 :(得分:0)
这是一个这样做的例子。它构建简单的匹配索引,然后按相关性按降序排序(第一个是最好的)。代码:
function searchByRelevance(search, data) {
let props = Object.getOwnPropertyNames(search);
return data.map((value) => { // Build match index
let match = 0;
for(let prop of props) {
if (value[prop] !== search[prop]) {
break;
}
match++;
}
return {
value,
match,
tail: match
? Object.getOwnPropertyNames(value).length - match
: Infinity,
};
})
.filter((item) => item.match) // Filter matched items only
.sort((a, b) => { // Sort by relevance
if (a.match !== b.match) {
return -(a.match - b.match);
}
if (a.tail !== b.tail) {
return a.tail - b.tail;
}
return 0;
})
.map((item) => item.value) // Get values from index items
;
}
// Example with time test
console.time('generate');
let set = [
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234, "output": "hello"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234},
{"Title": "UserA", "Name": "Bob Smith", "Number": 123},
{"Title": "UserA", "Name": "Bob Smith"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 12333, "output": "hello"}
];
let data = [];
for(let i = 0; i < 10000; i++) {
data = [...data, ...set];
}
console.timeEnd('generate');
let search = {"Title": "UserA", "Name": "Bob Smith", "Number": 1234, "output": "hello"};
console.time('search');
let matches = searchByRelevance(search, data);
console.timeEnd('search');
console.log(matches); // Matched items sorted by relevance
在你的例子中搜索50K文档的集合需要大约17毫秒。
答案 4 :(得分:0)
通过对象属性从左向右移动是不可靠的,因为不保证以特定顺序返回对象属性。
您可以将分数分配给数据集中某个对象(大海捞针)可能出现的四种情况,与您想要找到(针)的匹配对象相比:
如果您为这四个中的每一个分配一个分数,您可以为两个中的任何一个(大海捞针和针)中的所有属性添加分数:这将为该特定行提供分数。
然后选择最佳匹配行,即得分最高的行。
function bestMatch(needle, haystack) {
return haystack
.map( row =>
[...new Set(Object.keys(needle).concat(Object.keys(row)))]
.reduce( (score, key, i) =>
score + (!(key in needle) ? -10
: !(key in row ) ? - 5
: needle[key] !== row[key] ? -30
: 5), 0) )
.reduce((best, score, i) => score > best[0] ? [score, i] : best, [-9999, i])
.pop();
}
// Sample data
var haystack = [
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234, "output": "hello"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234},
{"Title": "UserA", "Name": "Bob Smith", "Number": 123},
{"Title": "UserA", "Name": "Bob Smith"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 12333, "output": "hello"}
];
var needle = {"Title": "UserA", "Name": "Bob Smith", "Number": 122,"output": "hello"};
// Get best match
var i = bestMatch(needle, haystack);
// Show results
console.log('best match at index ', i);
console.log(haystack[i]);
&#13;
您可以在代码中看到上述4种情况的4个分数。你可以根据自己的喜好调整这些。您甚至可以根据属性的名称给出不同的分数,以便&#34; Title&#34;会得到更多的分数,等于&#34;数字&#34;值。
答案 5 :(得分:0)
如果我理解正确,那么您正在尝试制定匹配评估标准,其中未定义的值优于不同的值,以便
{{Title“:”UserA“,”Name“:”Bob Smith“,”Number“:2222}
更接近
{{Title“:”UserA“,”Name“:”Bob Smith“}
比
{{Title“:”UserA“,”Name“:”Bob Smith“,”Number“:123}
我建议将匹配计为正数,将不同值计为负值,将未定义计为中性:
function bestMatch(array, object) {
if (!array) {array = [];}
if (!object) {object = {};}
var best_index = -1, best_value = 0;
for (var i = 0; i < array.length; i++) {
if (array[i]) {
var matches = 0, total = 0;
for (var p in object) {
total++;
if (array[i][p]) {
if (array[i][p] == object[p]) {
matches++;
} else {
matches--;
}
}
}
var value = matches/total;
if (value > best_value) {
best_value = value;
best_index = i;
}
}
}
return best_index;
}
var bestIndex = bestMatch(
[
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234, "output": "hello"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 1234},
{"Title": "UserA", "Name": "Bob Smith", "Number": 123},
{"Title": "UserA", "Name": "Bob Smith"},
{"Title": "UserA", "Name": "Bob Smith", "Number": 12333, "output": "hello"}
],
{"Title": "UserA", "Name": "Bob Smith", "Number": 2222}
);
console.log(bestIndex); // 3
答案 6 :(得分:-1)
如果您可以将对象重组为
[
{item: UserA | Bob Smith | 12345 | hello},
{item: UserA | Bob Smith | 12345 | },
{item: UserA | Bob Smith | 123 |},
{item: UserA | Bob Smith},
{item: UserB | Bob Smith | 12333 | hello},
]
您可以使用.filter()函数来获取匹配的记录,例如
Array.prototype.filteredItem = function(key, value) {
return this.filter(function(f) { return f[key] === value; })
}
然后您可以将filteredItem用作:
var result =myArr.filteredItem("item", "UserB | Bob Smith | 12333 | hello");