2017-02-13 86 views
11

數組相似字符串比方說,我有不同的URL集合中的數組:集團在Node.js的

var source = ['www.xyz.com/Product/1', 'www.xyz.com/Product/3', 'www.xyz.com/Category/1', 'somestring'] 

什麼會遍歷數組,並將相似串入一個好辦法單獨陣列? 從例子中的所需的輸出以上將是:

var output = [ 
    ['www.xyz.com/Product/1', 'www.xyz.com/Product/3'], 
    ['www.xyz.com/Category/1'], 
    ['somestring'] 
]; 

條件

  • source所有的數據項可以是隨機串
  • 邏輯必須能夠比較和組大約100' 000件物品在有意義的時間

我找到了string-similarity library,它提供了將一個字符串與字符串集合進行比較的可能性。一種方法是迭代源代碼,將每個項目與源集合進行比較,並應用規則對具有相似分數的項目進行分組。不過我想這樣做效率很低。

有人可以建議我一種有效的方法來完成我所需要的嗎?

+0

所以在這個例子中有一個清晰的模式,但它似乎是你問關於可能是任何東西的字符串?那是對的嗎? – aw04

+0

@ aw04是的,沒有明確的模式可以是任何字符串。正如我寫道:源內的所有項目可以是隨機字符串 – enyce12

+1

好運然後:) – aw04

回答

9

我能想到的最佳解決方案是將字符串與對方進行比較,並測試它們的不同之處。存在着這樣做,這是Levenshtein distance算法的算法:

的Levenshtein距離度量是用於測量兩個序列之間的差異 一個字符串。非正式地,兩個詞之間的Levenshtein距離 是將一個詞改爲另一個詞所需的單字符編輯 (即插入,刪除或替換)的最小數量。


我們可以很容易對fast-levenshtein module頂部創建的Levenshtein濾波器:

const levenshtein = require('fast-levenshtein'); 

const levenshteinFilter = (source, maximum = 5) => { 
    let _source, matches, x, y; 
    _source = source.slice(); 
    matches = []; 
    for (x = _source.length - 1; x >= 0; x--) { 
    let output = _source.splice(x, 1); 
    for (y = _source.length - 1; y >= 0; y--) { 
     if (levenshtein.get(output[0], _source[y]) <= maximum) { 
     output.push(_source[y]); 
     _source.splice(y, 1); 
     x--; 
     } 
    } 
    matches.push(output); 
    } 
    return matches; 
} 

let source = ['www.xyz.com/Product/1', 'www.xyz.com/Product/3', 'www.xyz.com/Category/1', 'somestring']; 
let output = levenshteinFilter(source); 
// [ [ 'www.xyz.com/Product/1', 'www.xyz.com/Product/3' ], 
// [ 'www.xyz.com/Category/1' ], 
// [ 'somestring' ] ] 

可以在函數的自變量2限定的最大可接受距離(默認爲5)。

+1

即使我提出了一個庫使用相同的算法您的解決方案正在工作。我還沒有測量性能,但謝謝你的答案! – enyce12

+0

應該是'levenshtein.get('? –

+0

@JohnJones謝謝你注意到這一點。 – 2017-04-25 23:21:48

0

你沒有充實你的意圖,但如果面臨從隨機乾草堆中找到最近鄰居的選定項目的任務,我可能會嘗試構建一棵哈希樹。或者,這可能是作弊,我會讓圖書館爲我做。 lunr.js基本上是一個純JS的lucene索引,我會推入你的數組,並查詢它以獲得相似的字符串。我之前在lunr.js中有非常大的數據集,並且性能非常高,在附近的elasticsearch集羣上沒有蠟燭,但仍然令人印象深刻。

如果你提供了一些你想要做什麼的更多細節,我可以給出一些更多的細節,甚至可能是一些示例代碼。

0

如果源代碼包含所有隨機地址,則下面的函數將給出問題中所示的預期輸出。

function filter (source) { 
    var output = [] 
    source.forEach((svalue) => { 
    if (output.length === 0) { 
     output.push([svalue]) 
    } else { 
     var done = false 
     output.forEach((tarr) => { 
     if (!done) { 
      tarr.forEach((tvalue) => { 
      if (svalue.indexOf('/') > -1 && svalue.split('/').slice(0, 2).join('/') == tvalue.split('/').slice(0, 2).join('/')) { 
       tarr.push(svalue) 
       done = true 
      } 
      }) 
     } 
     }) 
     if (!done) { 
     output.push([svalue]) 
     done = true 
     } 
    } 
    }) 
    return output 
} 
0

根據您的示例測試,我建議您實施Radix Tree or Prefix Tree來存儲字符串。之後,您可以定義一個標準來對這些字符串進行聚類。