按单词对c#列表进行排序



我想按单词对c#列表进行排序。假设我有一个c#对象列表,其中包含以下单词:

[{id:1, name: "ABC"},
 {id:2, name: "XXX"},
 {id:3, name: "Mille"},
 {id:4, name: "YYY"},
 {id:5, name: "Mill",
 {id:6, name: "Millen"},
 {id:7, name: "OOO"},
 {id:8, name: "GGGG"},
 {id:9, name: null},
 {id:10, name: "XXX"},
 {id:11, name: "mil"}]  

如果用户传递Mil作为搜索键,我想返回所有以搜索键&然后是所有不符合条件的单词&按字母顺序排序。

我能想到的最简单的方法是在结果集上运行for循环,将所有以search key开头的单词放入一个列表中,并将重命名单词放入另一个列表中。对第二个列表进行排序,然后将两个列表组合以返回结果。

我想知道是否有一种更聪明或内置的方法来获得所需的结果。

当然!您将根据是否存在匹配进行排序,然后按名称排序,如下所示:

var results = objects.OrderByDescending(o => o.Name.StartsWith(searchKey))
                     .ThenBy(o => o.Name);

注意,false在排序中出现在true之前,所以您需要使用OrderByDescending

正如AlexD指出的,名称可以为空。你得决定怎么处理这件事。最简单的方法是使用o.Name?.StartsWith(searchKey) ?? false,但您必须根据自己的需要做出决定。而且,并不是所有的Linq场景都支持null传播(我想到了Linq To Entities)。

应该这样做,但可能有一个更快的方法,也许使用GroupBy的某种方式。

var sorted = collection
    .Where(x => x.Name.StartsWith(criteria))
    .OrderBy(x => x.Name)
    .Concat(collection
           .Where(x => !x.Name.StartsWith(criteria))
           .OrderBy(x => x.Name))

您可以这样尝试GroupBy:

var sorted = collection
  .GroupBy(item => item.Name.StartsWith(criteria))
  .OrderByDescending(chunk => chunk.Key)
  .SelectMany(chunk => chunk
    .OrderBy(item => item.Name));
  • 将物品分为两组(符合和不符合标准)
  • 整体排序(第一个满足)
  • 在每组内订购物品
  • 最后合并项目

没有c#特定的方法来解决这个问题,但听起来你真的在寻找算法设计指南。

你应该先对列表排序。如果这是一个静态列表,您应该始终保持它的排序。如果列表很大,你可以考虑使用不同的数据结构(二叉搜索树,跳跃表等),这对这种情况更优化。

排序后,查找匹配元素就变成了简单的二分查找。将匹配的元素移动到结果集的开头,然后返回。

在select中添加一个匹配的指示符,然后对其进行排序:

void Main()
{
    word[] Words = new word[11]
    {new word {id=1, name= "ABC"},
    new word {id=2, name= "XXX"},
    new word {id=3, name= "Mille"},
    new word {id=4, name= "YYY"},
    new word {id=5, name= "Mill"},
    new word {id=6, name= "Millen"},
    new word {id=7, name= "OOO"},
    new word {id=8, name= "GGGG"},
    new word {id=9, name= null},
    new word {id=10, name= "XXX"},
    new word {id=11, name= "mil"}};
    var target = "mil";
    var comparison = StringComparison.InvariantCultureIgnoreCase;
    var q =  (from w in Words
              where w.name != null
              select new {
                           Match = w.name.StartsWith(target, comparison)?1:2, 
                           name = w.name})
                .OrderBy(w=>w.Match).ThenBy(w=>w.name);
    q.Dump();       
}
public struct word
{
    public int id;
    public string name;
}

这可能并不容易,但您可以创建一个实现IComparable Interface的类,并拥有一个由CompareTo使用的属性Mil。

那么你可以直接调用List.Sort()。你可以传递一个比较器给list。sort。

这可能是最有效的,你可以就地排序,而不是产生一个新的List。

该方法平均为O(n log n)次运算,其中n为Count;在最坏的情况下,它是一个O(n ^ 2)的操作。

 public int CompareTo(object obj) 
 {
    if (obj == null) return 1;
    Temperature otherTemperature = obj as Temperature;
    if (otherTemperature != null)
    {
        if(string.IsNullOrEmpty(Mil) 
            return this.Name.CompareTo(otherTemperature.Name); 
        else if(this.Name.StartsWith(Mill) && otherTemperature.Name.StartsWith(Mill)
            return this.Name.CompareTo(otherTemperature.Name);
        else if(!this.Name.StartsWith(Mill) && !otherTemperature.Name.StartsWith(Mill)
            return this.Name.CompareTo(otherTemperature.Name); 
        else if(this.Name.StartsWith(Mill))
            return 1;
        else 
            return 0;
    }
    else
       throw new ArgumentException("Object is not a Temperature");
 }

您将需要添加您希望null Name如何排序

首先创建一个匹配的单词列表,排序。然后将所有未被添加到第一个列表的单词添加到该列表中,也进行了排序。

public IEnumerable<Word> GetSortedByMatches(string keyword, Word[] words)
{
    var result = new List<Word>(words.Where(word => word.Name.StartsWith(keyword))
        .OrderBy(word => word.Name));
    result.AddRange(words.Except(result).OrderBy(word => word.Name));
    return result;
} 

一些注释建议它应该是不区分大小写的。那就是

public IEnumerable<Word> GetSortedByMatches(string keyword, Word[] words)
{
    var result = new List<Word>(
        words.Where(word => word.Name.StartsWith(keyword, true)) //<-- ignoreCase
        .OrderBy(word => word.Name));
    result.AddRange(words.Except(result).OrderBy(word => word.Name));
    return result;
} 

相关内容

  • 没有找到相关文章

最新更新