2016-10-31 58 views
1

如果以下代表我的陣列,如何找到數組中對象的最佳匹配?

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

什麼是最佳匹配?最大化從左到右的相等值的數量直到它們不同? – trincot

+0

是的!這是正確的 –

+0

而不是顯示您的數據打印,你可以顯示你的實際數據結構,所以沒有誤解? – trincot

回答

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> 
+0

這適用於我!謝謝!我會看到這裏的答案是最優的,然後馬上選擇它! –

-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"); 
+0

這不是「最喜歡」它是「完全相等」。 –

0

而不是通過每一次循環,你可以嘗試繪製數組中返回一個分數的每一項功能,然後獲得與指數最高分?

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)); 

這應該保持最高等於最高分和索引等於數組中的該項的索引。

+0

感謝您的回答! –

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 

花費大約17毫秒來搜索50K文檔,比如在你的例子中。

+0

所以如果其他對象每個都有其他的屬性,它仍然會匹配:( –

+0

這對我來說並不清楚,所以你的意思是如果對象沒有其他選項而不是查詢就應該匹配對象,如果沒有這種屬性存在於查詢中應該匹配,對嗎? –

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]);

您可以在代碼中看到給上述4種情況的分數。你可以根據自己的喜好調整這些。您甚至可以根據房產的名稱給出不同的分數,因此,對於「標題」,相同的值將給予相同的「數量」值更多的分數點。

0

如果我理解正確,您正在嘗試制定匹配評估標準,其中未定義值優於不同值,以便
{「Title」:「UserA」,「Name」:「Bob Smith」, 「編號」:2222}
接近
{ 「標題」: 「用戶A」, 「姓名」: 「鮑勃·史密斯」}

{ 「標題」: 「用戶A」, 「名稱」:「鮑勃史密斯「,」數字「: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 
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"} 
相關問題