我想按字词排序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键开头的单词放入一个列表中,并将重命名单词放入另一个列表中。对第二个列表进行排序,然后将它们组合在一起以返回结果。
我想知道是否有更智能或内置的方式来获得理想的结果。
答案 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));
答案 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;
}