按字

时间:2016-06-30 21:38:25

标签: c# .net linq sorting c#-4.0

我想按字词排序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键开头的单词放入一个列表中,并将重命名单词放入另一个列表中。对第二个列表进行排序,然后将它们组合在一起以返回结果。

我想知道是否有更智能或内置的方式来获得理想的结果。

7 个答案:

答案 0 :(得分:8)

当然!您将按匹配的顺序排序,然后按名称排序,如下所示:

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

请注意false排在true之前,因此您需要使用OrderByDescending

正如AlexD指出的那样,名称可以为null。您必须决定如何对待此事。最简单的方法是使用o.Name?.StartsWith(searchKey) ?? false,但您必须根据自己的需要做出决定。此外,并非所有Linq场景都支持空传播(想到Linq To Entities)。

答案 1 :(得分:5)

这应该这样做,但可能有更快的方法,可能以某种方式使用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))

答案 2 :(得分:5)

您可以尝试这样GroupBy

var sorted = collection
  .GroupBy(item => item.Name.StartsWith(criteria))
  .OrderByDescending(chunk => chunk.Key)
  .SelectMany(chunk => chunk
    .OrderBy(item => item.Name));
  • 将项目分为两组(符合且不符合标准)
  • 整体订购团体(第1次见面)
  • 每个组内的订单项目
  • 最后合并项目

答案 3 :(得分:1)

没有任何C#特定的解决方案,但听起来你真的在寻找算法设计指导。

您应该先对列表进行排序。如果这是一个静态列表,您应该始终对其进行排序。如果列表很大,您可以考虑使用更适合此场景的不同数据结构(二进制搜索树,跳过列表等)。

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

答案 4 :(得分:1)

在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;
}

答案 5 :(得分:0)

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

然后你可以拨打List.Sort()。并且您可以将IComparer传递给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");
 }

您需要添加“名称”排序方式

答案 6 :(得分:0)

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

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;
} 
相关问题