对集合进行排序并根据特定条件对结果进行排名

说我有以下内容

var searches = new ObservableCollection(); 

searches包含书籍对象

 public class Book { public string Title { get; set;} public string Desc {get; set;} } 

我想通过匹配的字符串对searches进行排序。 首先,它检查Title不是根据Title开头的搜索字符串的接近程度对它们进行排名。 接下来,它检查Desc并根据搜索字符串从描述的开头出现的接近程度对它们进行排名。

例如,如果我有

书1
标题:ABC书名
描述:书1的描述

书2
标题:仅限书名
说明:第2册的描述中有一个ABC

书3
标题:书名ABC
描述:ABC在一开始

所以,假设搜索关键字是ABC ,我希望对searches进行排序,以便获得以下内容。 结果将更高优先级放在标题中包含搜索字符串的项目中。

书1
标题:ABC书名
描述:书1的描述

书3
标题:书名ABC
描述:ABC在一开始

书2
标题:仅限书名
说明:第2册的描述中有一个ABC

我如何使用LINQ实现这一目标?

您可以使用排名function为每本书定义“分数”,然后按分数排序。

 var searchString = "ABC"; var results = books.Select(b => new { Book = b, Rank = RankBook(b, searchString) }) .OrderBy(r => r.Rank) .Select(r => r.Book.Title); 

并且排名function:

 private int RankBook(Book b, string searchString) { int rank = 0; if (b.Title.Contains(searchString)) rank += 10; if (b.Desc.Contains(searchString)) rank += 5; return rank; } 

这就是说:发现在title = 10分,发现在desc = 5分,所以你得到最高分的最相关的书。

您可以使用OrderBy和ThenBy

 var searches = new ObservableCollection(); searches.Add(new Book() { Desc = "The description of book 1", Title = "ABC Book Title" }); searches.Add(new Book() { Desc = "Book Title Only", Title = "There's an ABC in the description of book 2" }); searches.Add(new Book() { Desc = "Book Title ABC", Title = "ABC is in the beginning" }); var ordered = new ObservableCollection(searches.OrderBy(book => book.Title).ThenBy(book => book.Desc.Contains("ABC"))); 

更新

我添加了一个排名系统,希望能帮助您找到所需的内容。 我使用的只是IndexOf来确定条件的位置并将其存储在Book对象的属性中。 我的另一个建议是你为你的书创建一个独立的集合(使用inheritance),这样你就可以根据需要自定义它,而不必在对象本身的上下文之外编写太多代码

 public class BookCollection : ObservableCollection // Notice the Inheritance to ObservableCollection { public void SetCriteria(string search) { if(string.IsNullOrEmpty(search)) return; foreach (var book in this) { if(book.Title.Contains(search)) book.TitleRank = book.Title.IndexOf(search, StringComparison.InvariantCulture); if(book.Desc.Contains(search)) book.DescRank = book.Desc.IndexOf(search, StringComparison.InvariantCulture); } var collection = new List(base.Items.OrderBy(book => book.Title) .ThenBy(book => book.Desc) .ThenBy(book => book.TitleRank) .ThenBy(book => book.DescRank)); Items.Clear(); collection.ForEach(Add); collection.Clear(); } } public class Book { public string Title { get; set; } public string Desc { get; set; } public int TitleRank { get; internal set; } public int DescRank { get; internal set; } } 

现在要使用这个新的集合,你所要做的就是这样称呼它。

 var collection = new BookCollection(); collection.Add(new Book { Desc = "Book Title ABC", Title = "ABC is in the beginning" }); // Add your other books here........ collection.SetCriteria("ABC"); // your new collection is now sorted and ready to use, no need to write any extra sorting code here 

请记住,如果您需要为排序添加更多条件,则必须在SetCriteria方法中执行此操作。 希望这可以帮助。

感谢@ Patel和Stefano的建议,我得出了以下解决方案

 var sorted = searches.Select(tile => new { TileViewModel = tile, Rank = rankResult(tile, text) }) .OrderByDescending(r => r.Rank) .Select(r => r.TileViewModel); SearchResultsTilesVM = new ObservableCollection(sorted); 

获取关键字位置的方法。 如果在标题中找到匹配项,我会添加额外的点数。

  private int rankResult(TileViewModel vm, string keyword) { double rank = 0; //Added 100 to give stronger weight when keyword found in title int index = vm.Title.IndexOf(keyword, StringComparison.InvariantCultureIgnoreCase); if (index >= 0 ) { rank = (double)(vm.Title.Length - index) / (double)vm.Title.Length * 100 + 100; } int index2 = vm.Information.IndexOf(keyword, StringComparison.InvariantCultureIgnoreCase); if (index2 >= 0) { rank += (double)(vm.Information.Length - index2) / (double)vm.Information.Length * 100; } return Convert.ToInt32(rank); }