简体   繁体   中英

How to perform word search using LINQ?

I have a list which contains the name of suppliers. Say

SuppId   Supplier Name
----------------------------------
1        Aardema & Whitelaw
2        Aafedt Forde Gray
3        Whitelaw & Sears-Ewald

using following LINQ query

supplierListQuery = supplierListQuery.Where(x => x.SupplierName.Contains(SearchKey));

I can return records correctly in the following conditions,

1) If i am using search string as "Whitelaw & Sears-Ewald" it will return 3rd record.

2) If i am using "Whitelaw" or " Sears-Ewald" it will return 3rd record.

But how can i return 3rd record if i am giving search string as "Whitelaw Sears-Ewald" . It always returns 0 records.

Can i use ALL to get this result, but i dont know how to use it for this particular need.

What I usually do in this situation is split the words into a collection, then perform the following:

var searchopts = SearchKey.Split(' ').ToList();
supplierListQuery = supplierListQuery
    .Where(x => searchopts.Any(y=> x.SupplierName.Contains(y)));

Thank you all for your quick responses. But the one which worked or a easy fix to handle this was timothyclifford's note on this. Like he said i alterd my answer to this

string[] filters = SearchKey.ToLower().Split(new[] { ' ' });
objSuppliersList = (from x in objSuppliersList
                    where filters.All(f => x.SupplierName.ToLower().Contains(f))
                    select x).ToList();

Now it returns the result for all my serach conditions.

This works for me:

IEnumerable<string> keyWords = SearchKey.Split('');

supplierListQuery = supplierListQuery
      .AsParallel()
      .Where
      (
         x => keyWords.All
         (
              keyword => x.SupplierName.ContainsIgnoreCase(keyword)
         )
      );

You need to use some sort of string comparer to create your own simple Search Engine and then you can find strings that are most likely to be included in your result :

public static class SearchEngine
{

    public static double CompareStrings(string val1, string val2)
    {
        if ((val1.Length == 0) || (val2.Length == 0)) return 0;
        if (val1 == val2) return 100;

        double maxLength = Math.Max(val1.Length, val2.Length);
        double minLength = Math.Min(val1.Length, val2.Length);
        int charIndex = 0;
        for (int i = 0; i < minLength; i++) { if (val1.Contains(val2[i])) charIndex++; }

        return Math.Round(charIndex / maxLength * 100);
    }

    public static List<string> Search(this string[] values, string searchKey, double threshold)
    {
        List<string> result = new List<string>();
        for (int i = 0; i < values.Length; i++) if (CompareStrings(values[i], searchKey) > threshold) result.Add(values[i]);
        return result;
    }
}

Example of usage :

string[] array = { "Aardema & Whitelaw", "Aafedt Forde Gray", "Whitelaw & Sears-Ewald" };

var result = array.Search("WhitelawSears-Ewald", 80);
// Results that matches this string with 80% or more

foreach (var item in result)
{
   Console.WriteLine(item);
}

Output: Whitelaw & Sears-Ewald

Because "Whitelaw" appears in both you will get both records. Otherwise there is no dynamic way to determine you only want the last one. If you know you only have these 3 then append .Last() to get the final record.

supplierListQuery = supplierListQuery.Where(x => x.SupplierName.Contains(SearchKey.Split(' ')[0]));

If you want an easy (not very handy) solution,

var result = supplierListQuery
                      .Select(x => normalize(x.SupplierName))
                      .Where(x => x.Contains(normalize(SearchKey)));

string normalize(string inputStr)
{
    string retVal = inputStr.Replace("&", "");
    while (retVal.IndexOf("  ") >= 0)
    {
        retVal = retVal.Replace("  ", " ");
    }
    return retVal;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM