2009-11-12 105 views
1
 query = Files 
      .Where(file => file.Fileinfo.Name.ToUpper().Contains(textBox1.Text.ToUpper())) 
      .Take(7).ToList(); 

我討厭問這個問題,但我根本沒有任何進展!這看起來應該是一件小事,但我沒有任何運氣。c#「like/contains」通過列表搜索

上述查詢需要通過文件名列表進行搜索。它會將搜索結果返回到排名前7位的相關結果列表中。該事件發生在「KeyPress」。

雖然,這是非常不莊重的,也有一些相當奇怪的結果。

例如:如果我的列表中的項目有一個名稱:「ZeroWidthSplit」 如果我的文本框包含「Z」,它可以工作。如果它包含ZE它可以工作。如果它包含「ZER」它仍然顯示。 如果我輸入ZERO它會從搜索結果中消失!

所以我想我的問題是:你如何通過文件列表進行搜索,並使其返回前7個最相關的結果。

哦,如果只有4個相關的結果,那也沒關係。該限制只是7.

又如:如果我寫 「sum of」 作爲搜索查詢

F.X。它返回:

  1. 77 - 質數之和連續的素數五千 不同的方式
  2. 52總和低於 百萬

如果我寫 「sum of p」 返回:

  1. 77 - 質數五千之和 不同的方式

如果我寫「sum of c」它沒有返回值...

我可以給你更多的奇怪的例子。

+0

你還有7個結果回來? – manji 2009-11-12 10:39:30

+0

它確實返回結果,它們只是一點點不準確 - 然後是「零」錯誤,這只是一個例子。許多其他名字也是如此。 如果沒有很多相關的結果,我的查詢只會顯示相關的結果。我只是將StringComparison枚舉的最大值設置爲7. – CasperT 2009-11-12 10:43:08

回答

1

在您的方案中如何定義「最相關的」? 如果你只是使用Contains,結果會錯過很多「相關」的結果,這些結果與精確子串的形式不匹配。

你期待什麼樣的投入? 如果輸入的只是一個字,那麼這個算法可能會爲你工作:

健身應作爲 長度在 輸入字符串中找到目標字符串的最長公共子 來計算,分目標字符串長度爲 。例如,HPPLE 與APPLE 相比得分爲0.8,因爲在HPPLE中發現的APPLE 的最長子串是4個字母長, 是APPLE長度的.8。 此外,處罰由 0.1分數爲每個外來字母輸入串具有超過的 目標串的長度。例如。哈普勒 有得分.9相比蘋果, 因爲它是1個字母長, 否則有完整的子 蘋果。請注意,這使得 候選詞可能有 爲負值。

當然還有很多其他更好的算法來計算距離。 如果輸入可能包含多個單詞,那麼使用其他算法計算字符串之間的「距離」可能會更好。

和Umm ...你原來的查詢沒有結果進行排序,這樣你就不會錄取前7個最相關的人,你只是走前7個結果的序列。

爲了總結的東西了,這可能會爲你工作:

using System; 
using System.Collections.Generic; 
using System.Linq; 

public static class StringDistanceUtil { 

    /// <summary> 
    /// Returns the longest common substring of the given two arguments. 
    /// </summary> 
    /// <param name="first"> 
    /// the first string 
    /// </param> 
    /// <param name="second"> 
    /// the second string 
    /// </param> 
    /// <returns> 
    /// the longest common substring of the given two arguments 
    /// </returns> 
    public static string LongestCommonSubstringWith(this string first, string second) { 
     // could have used dynamic programming, or generalized suffix tree 
     // to solve the LCS problem, but here we'll just stick to simplicity 

     var start = 0; // The start in a of the longest found so far 
     var len = 0; // The length of the longest found so far 
     for (var i = 0; i < first.Length - len; ++i) { 
      for (var j = first.Length - i; j > len; --j) { 
       if (second.Contains(first.Substring(i, j))) { 
        start = i; 
        len = j; 
        break; // Exit the inner loop 
       } 
      } 
     } 

     return first.Substring(start, len); 
    } 

    /// <summary> 
    /// Returns the distance of two strings. 
    /// </summary> 
    /// <param name="str"> 
    /// a string 
    /// </param> 
    /// <param name="target"> 
    /// the target string 
    /// </param> 
    /// <returns> 
    /// the distance from a string to the target string 
    /// </returns> 
    public static double DistanceFrom(this string str, string target) { 
     var strLen = str.Length; 
     var targetLen = target.Length; 
     var ratio = str.LongestCommonSubstringWith(target).Length 
       /(double) targetLen; 
     var penalty = 
      (strLen > targetLen) ? 
       (0.1 * (strLen - targetLen)) 
       : 0; 
     return ratio - penalty; 
    } 

    static void Main(string[] args) { 
     var list = new List<string> { 
      "zero", 
      "range", 
      "shot", 
      "shoot", 
      "hop", 
      "rage", 
      "fang", 
      "age" 
     }; 
     var target = "zero_range_shot"; 
     var top5mostRelated = list 
      .OrderByDescending(str => str.ToUpper().DistanceFrom(target.ToUpper())) 
      .Take(5).ToList(); 
     foreach (var str in top5mostRelated) Console.WriteLine(str); 
    } 
} 

,輸出是: 範圍 零 拍攝 拍攝 方

1

我不知道這是問題的根源,但我會通過重構代碼開始,這樣textBox1.Text是隻讀一次:

string theText = textBox1.Text.ToUpper(); 

query = Files 
      .Where(file => file.Fileinfo.Name.ToUpper().Contains(theText)) 
      .Take(7).ToList(); 
4

錯誤聽起來很奇怪,但作爲Konamiman指出,雖然我不喜歡使用ToUpper或ToLower,但重構一點也不會傷害。我會這樣做:

string theText = textBox1.Text; 

query = Files 
      .Where(file => file.Fileinfo.Name.IndexOf(theText, 
       StringComparison.OrdinalIgnoreCase) != -1) 
      .Take(7).ToList(); 
+0

+1。我總是忘記它存在。 – Konamiman 2009-11-12 10:58:46

+0

這很聰明。不幸的是,搜索結果是一樣的 – CasperT 2009-11-12 11:36:56

0

也許O在零是實際的數字0而不是字母O?

+0

對不起,沒有:)這只是一個例子。讓我編輯我的OP,並向你展示另一個例子 – CasperT 2009-11-12 11:50:38

+0

這將是一個真正的大哦!如果這是問題的時刻。 :-) – Konamiman 2009-11-12 11:51:16

+0

增加了另一個例子。我有一噸 – CasperT 2009-11-12 11:53:33

0

你確認在textbox1.Text財產調試器?

也許TextChanged將是這方面比KeyPress更好的事件?