2016-06-13 33 views
1

Dies ist mein Code:Synonyme für Wörter von Levenshtein Entfernung

public void SearchWordSynonymsByLevenstein() 
{ 
    foreach (var eachWord in wordCounter) 
    { 
     foreach (var eachSecondWord in wordCounter) 
     { 
      if (eachWord.Key.Length > 3) 
      { 
       var score = LevenshteinDistance.Compute(eachWord.Key, eachSecondWord.Key); 
       if (score < 2) 
       { 
        if(!wordSynonymsByLevenstein.Any(x => x.Value.ContainsKey(eachSecondWord.Key))) 
        { 
         if (!wordSynonymsByLevenstein.ContainsKey(eachWord.Key)) 
         { 
          wordSynonymsByLevenstein.Add(eachWord.Key, new Dictionary<string, int> { { eachSecondWord.Key, eachSecondWord.Value } }); 
         } 
         else 
         { 
          wordSynonymsByLevenstein[eachWord.Key].Add(eachSecondWord.Key, eachSecondWord.Value); 
         } 
        } 
       } 
      } 
     } 
    } 
} 

Mein wordCounter ist Dictionary<string, int> wo Schlüssel meine jedes Wort und Wert zählen, wie viele dieses Wort in den Dokumenten vorhanden ist. Etwas wie ein Beutel voller Worte. Ich muss Synonyme für eachWord von anderen eachSecondWord suchen. Diese Methode kostet zu viel Zeit. Die Zeit steigt exponentiell. Gibt es eine andere Möglichkeit, die Zeit zu reduzieren?

+0

Muss 'wordSynonymsByLevenstein' wirklich ein 'Dictionary >' sein? Warum nicht einfach eine 'Dictionary >'? Sie können das verwenden, um die "Synonyme" zu finden, dann gehen Sie zu "wordCounter" für die Zählungen. – juharr

+0

Danke, später mache ich das: 'if (wordSynonymsByLevenstein.TryGetValue (eachMainWord, aus isThisWord)) { \t foreach (var eachWw in isThisWord) \t { \t \t mainWordWithSynonyms.Add (eachWw.Key); \t \t fullCounted = vollzählig + jederWWert; \t} \t var distintedWord = mainWordWithSynonyms.DistinctBy (x => x) .ToList(); \t if (mainFoundWords.Any (x => distinctedWord.Any (y => y == x)) && compFoundWords.Any (x => distinctedWord.Any (y => y == x))) { \t \t \t relationScore = relationScore + ((doppelt) 1/(doppelt) fullCounted); \t \t gezählteEqualWord ++; \t} } '' So wordSynonymsByLevenshtein' muss das sein 'Dictionary' – Sidron

+0

Was ich sagen will ist, dass, wenn' wordSynonymsByLevenstein' ein 'Wörterbuch ' dann würden Sie die 'isThisWord' raus und es wäre die Liste der Wörter, also ändere 'eachWw.Key' in' eachWw' und 'eachWw.Value' in' wordCounter [eachWw] ' – juharr

Antwort

1

Zunächst einmal nehme ich an, dass Sie kein Wort mit sich selbst in der wordSynonymsByLevenstein Sammlung verbinden möchten. Zweitens können Sie diejenigen überspringen, von denen Sie wissen, dass sie Ihre < 2 Punkte Anforderung nicht erfüllen, indem Sie die Länge der Wörter vergleichen.

public void SearchWordSynonymsByLevenstein() 
{ 
    foreach (var eachWord in wordCounter) 
    { 
     foreach (var eachSecondWord in wordCounter) 
     { 
      if (eachWord.Key == eachSecondWord.Key 
       || eachWord.Key.Length <= 3 
       || Math.Abs(eachWord.Key.Length - eachSecondWord.Key.Length) >= 2) 
      { 
       continue; 
      } 
      var score = LevenshteinDistance.Compute(eachWord.Key, eachSecondWord.Key); 
      if (score >= 2) 
      { 
       continue; 
      } 

      if(!wordSynonymsByLevenstein.Any(x => x.Value.ContainsKey(eachSecondWord.Key))) 
      { 
       if (!wordSynonymsByLevenstein.ContainsKey(eachWord.Key)) 
       { 
        wordSynonymsByLevenstein.Add(eachWord.Key, new Dictionary<string, int> { { eachSecondWord.Key, eachSecondWord.Value } }); 
       } 
       else 
       { 
        wordSynonymsByLevenstein[eachWord.Key].Add(eachSecondWord.Key, eachSecondWord.Value); 
       } 
      } 

     } 
    } 
} 

Ihre Anforderung, die mit dem if(!wordSynonymsByLevenstein.Any(x => x.Value.ContainsKey(eachSecondWord.Key))) ausgedrückt wird, ist nicht besonders ausgeprägt oder gerade nach vorne, aber wenn Sie mit mehr als einem zugehörigen kein Wort wollen, dann können Sie zusätzlich eine HashSet<string> und wie können Sie Worte hinzufügen Fügen Sie sie zu diesem HashSet hinzu und prüfen Sie, ob das nächste Wort da ist, bevor Sie fortfahren, anstatt die verschachtelten Wörterbücher zu durchlaufen.

public void SearchWordSynonymsByLevenstein() 
{ 
    var used = new HashSet<string>(); 
    foreach (var eachWord in wordCounter) 
    { 
     foreach (var eachSecondWord in wordCounter) 
     { 
      if (eachWord.Key == eachSecondWord.Key 
       || eachWord.Key.Length <= 3 
       || Math.Abs(eachWord.Key.Length - eachSecondWord.Key.Length) >= 2) 
      { 
       continue; 
      } 
      var score = LevenshteinDistance.Compute(eachWord.Key, eachSecondWord.Key); 
      if (score >= 2) 
      { 
       continue; 
      } 

      if(used.Add(eachSecondWord.Key))) 
      { 
       if (!wordSynonymsByLevenstein.ContainsKey(eachWord.Key)) 
       { 
        wordSynonymsByLevenstein.Add(eachWord.Key, new Dictionary<string, int> { { eachSecondWord.Key, eachSecondWord.Value } }); 
       } 
       else 
       { 
        wordSynonymsByLevenstein[eachWord.Key].Add(eachSecondWord.Key, eachSecondWord.Value); 
       } 
      } 

     } 
    } 
} 

Hier verwendete ich if(used.Add(eachSecondWord.Key))) weil Addtrue wenn das Wort hinzugefügt wurde zurückkehren und false, wenn es bereits in der HashSet war.

+0

Danke für die tollen Tipps :) Diese 'Math.Abs' helfen wirklich und reduzieren die Zeit.Ich ändere dieses Wörterbuch auf das, was Sie gesagt haben, und erhalte den Zählwert von 'wordCounter'. Vielen Dank :) – Sidron