c#“like / contains”搜索列表

时间:2009-11-12 10:34:37

标签: c# linq

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

我讨厌问这个问题,但我根本没有任何进展!这应该是一项微不足道的任务,但我没有任何运气。

上述查询需要搜索文件名列表。它会将搜索结果返回到列表中,其中包含前7个最相关的结果。该事件发生在“KeyPress”。

虽然,它非常不经常,但也有一些非常奇怪的结果。

例如:如果我的列表中的项目具有名称,则为:“ZeroWidthSplit” 如果我的文本框包含“Z”,则可以正常工作。如果它包含ZE则有效。如果它包含“ZER”,它仍会显示。 如果我输入ZERO,它会从搜索结果中消失!

所以我想我的问题是:如何搜索文件列表,并使其返回前7个最相关的结果。

哦,如果只有4个相关结果,那也没关系。限制只有7个。

另一个例子:

F.x如果我将“sum of”写为搜索查询。它返回:

  1. 77 - 素数总和五千 不同的方式
  2. 以下52个连续素数之和 100万
  3. 如果我写“sum of p”,则返回:

    1. 77 - 素数总和五千 不同的方式
    2. 如果我写“sum of c”,则不返回任何内容......

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

5 个答案:

答案 0 :(得分:4)

这个错误听起来确实很奇怪,但正如Konamiman指出的那样,虽然我不喜欢使用ToUpper或ToLower,但一点点重构都不会受到影响。我将按以下方式进行:

string theText = textBox1.Text;

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

答案 1 :(得分:2)

您的方案中如何定义“最相关”? 如果你只使用Contains,那么结果会错过许多与精确子字符串形式不匹配的“相关”结果。

您期待什么样的输入? 如果输入只是一个单词,那么这个算法可能适合你:

  

适应度应计算为   最长公共子串的长度   在...中找到的目标字符串   输入字符串,除以长度   目标字符串。例如,HPPLE   与APPLE相比得分为.8,   自APPLE最长的子串   在HPPLE中找到4个字母长,   这是APPLE长度的.8。   另外,惩罚得分   对于每个无关字母,输入字符串的长度为0.1   目标字符串。例如。哈普勒   与APPLE相比得分为.9,   因为它长1个字母,而且   否则有完整的子串   苹果。请注意,这样做   候选词可能有   负分。

当然,还有很多其他更好的算法来计算距离。 如果输入可能包含多个单词,那么您可能最好使用其他算法来计算字符串之间的“距离”。

嗯......你的原始查询没有对结果进行排序,所以你没有选择前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);
    }
}

,输出为: 范围 零 射击 射击 芳

答案 2 :(得分:1)

我不知道这是问题的根源,但我首先要重构代码,以便textBox1.Text只读一次:

string theText = textBox1.Text.ToUpper();

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

答案 3 :(得分:0)

也许零中的O实际上是数字0而不是字母O?

答案 4 :(得分:0)

您是否在调试器中确认了textbox1.Text属性?

TextChanged而言,KeyPress可能比{{1}}更好?