简体   繁体   中英

Search list and order List by value max found c#

i like to confess that i am weak in LINQ. i have list with data. i want to search list fist by given value and then sort data by max occurance means which comes maximum time in rows.

        List<SearchResult> list = new List<SearchResult>() { 
            new SearchResult(){ID=1,Title="Cat"},
            new SearchResult(){ID=2,Title="dog"},
            new SearchResult(){ID=3,Title="Tiger"},
            new SearchResult(){ID=4,Title="Cat"},
            new SearchResult(){ID=5,Title="cat"},
            new SearchResult(){ID=6,Title="dog"},
        };

if i search & sort list with data like "dog cat" then output will be like

ID=1,Title=Cat
ID=4,Title=Cat
ID=5,Title=Cat
ID=2,Title=dog
ID=6,Title=dog

all cat will come first because this cat keyword found maximum time in all the rows and then dog found maximum time.

this below data will not come because it is not in search term

ID=3,Title=Tiger

looking for solution. thanks

UPDATE PORTION CODE

        List<SearchResult> list = new List<SearchResult>() { 
            new SearchResult(){ID=1,Title="Geo Prism 1995 - ABS #16213899"},
            new SearchResult(){ID=2,Title="Excavator JCB - ECU P/N: 728/35700"},
            new SearchResult(){ID=3,Title="Geo Prism 1995 - ABS #16213899"},
            new SearchResult(){ID=4,Title="JCB Excavator - ECU P/N: 728/35700"},
            new SearchResult(){ID=5,Title="Geo Prism 1995 - ABS #16213899"},
            new SearchResult(){ID=6,Title="dog"},
        };

        var to_search = new[] { "Geo", "JCB" };
        var result = list.Where(sr => to_search.Any(ts => String.Compare(ts, sr.Title, StringComparison.OrdinalIgnoreCase) == 0))
                         .GroupBy(sr => sr.Title.ToLower())
                         .OrderByDescending(g => g.Count());

        var matched = result.SelectMany(m => m);

        var completeList = matched.Concat(list.Except(matched));

        dataGridView2.DataSource = completeList.ToList();

i try to your logic in another apps but it is not working. according to logic three rows first come with GEO keyword and then next 2 rows comes with JCB and then unmatched rest comes. what i need to change in ur code. please help. thanks

This will filter your list and group it by Title , sorting the groups by their size.

List<SearchResult> list = new List<SearchResult>() { 
    new SearchResult(){ID=1,Title="Cat"},
    new SearchResult(){ID=2,Title="dog"},
    new SearchResult(){ID=3,Title="Tiger"},
    new SearchResult(){ID=4,Title="Cat"},
    new SearchResult(){ID=5,Title="cat"},
    new SearchResult(){ID=6,Title="dog"},
};

var to_search = new[] { "cat", "dog" };

var result = list.Where(sr => to_search.Any(ts => String.Compare(ts, sr.Title, StringComparison.OrdinalIgnoreCase) == 0))
                 .GroupBy(sr => sr.Title.ToLower())
                 .OrderByDescending(g => g.Count());

foreach (var group in result)
    foreach (var element in group)
        Debug.WriteLine(String.Format("ID={0},Title={1}", element.ID, element.Title));

Output:

ID=1,Title=Cat
ID=4,Title=Cat
ID=5,Title=cat
ID=2,Title=dog
ID=6,Title=dog

If you don't care about the actual grouping, just can flatten the list of groups with SelectMany .

(Note that this code will ignore the case of Title . I don't know if this is what you want or if it is a typo in code: you are using cat and Cat , and in your output it is only Cat , but dog is not capitalized.)

Edit:

To get the unmatched items, you can use Except :

var unmatched = list.Except(result.SelectMany(m => m)); // beware! contains the tiger!

Edit 2:

var result = list.Where(sr => to_search.Any(ts => String.Compare(ts, sr.Title, StringComparison.OrdinalIgnoreCase) == 0))
                 .GroupBy(sr => sr.Title.ToLower())
                 .OrderByDescending(g => g.Count());

var matched = result.SelectMany(m => m);

var completeList = matched.Concat(list.Except(matched));

foreach (var element in completeList)
    Debug.WriteLine(String.Format("ID={0},Title={1}", element.ID, element.Title));

Output

ID=1,Title=Cat
ID=4,Title=Cat
ID=5,Title=cat
ID=2,Title=dog
ID=6,Title=dog
ID=3,Title=Tiger

Edit 3

var result = from searchResult in list
             let key_string = to_search.FirstOrDefault(ts => searchResult.Title.ToLower().Contains(ts.ToLower()))
             group searchResult by key_string into Group
             orderby Group.Count() descending
             select Group;

I think the following should do the trick.

var searchText = "cat dog";
var searchResult = list
  .Select(i => new { 
       Item = i, 
       Count = list.Count(x => string.Compare(x.Title, i.Title, true) == 0)  // Add counter
  })
  .Where(i => searchText.Contains(i.Item.Title))
  .OrderByDescending(i => i.Count)
  .ThenBy(i => i.Item.ID)
  .ToList()

Update

If you want unmatched data at the end, you need to add another sorting property in the anonymous object.

var searchText = "cat dog";
var searchResult = list
  .Select(i => new { 
       Item = i, 
       Matched = searchText.Contains(i.Item.Title.ToUpper()),
       Count = list.Count(x => string.Compare(x.Title, i.Title, true) == 0)  // Add counter
  })
  .OrderByDescending(i => i.Matched)
  .ThenBy(i => i.Count)
  .ThenBy(i => i.Item.ID)
  .ToList()
IEnumerable<string> pets = new[] { "Cat", "dog", "Tiger", "Cat", "cat", "dog" };
var test = pets
    .Where(p=>p.ToUpperInvariant() == "CAT" || p.ToUpperInvariant() == "DOG")
    .GroupBy(p => p.ToUpperInvariant())
    .OrderByDescending(g => g.Count())
    .SelectMany(p => p);

foreach (string pet in test)
    Console.WriteLine(pet);

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