如何订购 IEnumerable<T> 以使特殊项目始终位于底部? [复制]
Posted
技术标签:
【中文标题】如何订购 IEnumerable<T> 以使特殊项目始终位于底部? [复制]【英文标题】:How do I order an IEnumerable<T> such that a special item is always at the bottom? [duplicate] 【发布时间】:2017-04-27 09:49:50 【问题描述】:我有一个 IEnumerable<string>
正在传递给我,其中包含以下项目:
现在我想要实现的是按字母顺序排列项目,但我想将 other
项目保留在最后。我已经继续使用OrderBy(i => i)
其中列出的项目如下:
佳能 惠普 利盟 其他 三星我想要的结果是
佳能 惠普 利盟 三星 其他我尝试过使用.OrderBy(i => i != "Other").ThenBy(i => i)
,但这会将Other
项目放在顶部。
谁能告诉我如何实现这一点。
【问题讨论】:
【参考方案1】:你必须使用OrderByDescending
,因为true
比false
“更高”
list.OrderByDescending(s => s != "Other")
.ThenBy(s => s);
你也可以使用
list.OrderBy(s => s == "Other" ? 1 : 0)
.ThenBy(s => s);
既然你已经问过了,这里有一些扩展方法可以简化它以备将来使用:
public static IEnumerable<T> OrderFirst<T>(this IEnumerable<T> sequence, Func<T, bool> predicate)
return sequence.OrderByDescending(predicate);
public static IEnumerable<T> OrderLast<T>(this IEnumerable<T> sequence, Func<T, bool> predicate)
return sequence.OrderBy(predicate);
示例用法:
var list = new List<string> "HP", "Other", "Samsung" ;
var otherLast = list.OrderLast(s => s == "Other").ToList();
【讨论】:
谢谢。我将如何将其转换为扩展方法,因为我将与其他一些IEnumerable<T>
或者(只是因为它稍微短一点)list.OrderBy(s => s == "Other").ThenBy(s => s);
@Code 你不需要做任何事情。您可以将多个字段与OrderBy
一起使用,就像Select
一样。如果您在OrderBy
中使用返回(s=="Other",s)
或Tuple.Create(s=="Other",s)
的表达式,您将实现您想要的。相当于SQL的ORDER BY a,b,c
@MatthewWatson 不短于 list.OrderBy(s=>(s=="Other",s))
,或 Tuple.Create 的等价物。我想知道性能差异会是什么。复制 vs 分配 vs(可能)多次迭代?
你的观点很好,我会坚持下去【参考方案2】:
我尝试过使用
.OrderBy(i => i != "Other").ThenBy(i => i)
,但这会将其他项目放在顶部。
所以你快到了,你只需要颠倒你的第一个标准的排序顺序:将OrderBy
替换为OrderByDesc
或将i != "Other"
替换为i == "Other
。
当然,明确一点也没有什么坏处:布尔值是如何排序的并不明显,所以我更喜欢:
.OrderBy(i != "Other" ? 1 : 2).ThenBy(i => i);
【讨论】:
感谢您的帮助【参考方案3】:另一个使用元组的选项:
list.OrderBy(s => Tuple.Create(s=="Other",s));
或者,在 C# 7 中:
list.OrderBy(s => (s=="Other",s));
OrderBy 需要一个返回排序依据的 key 的表达式。如果要按多个字段排序,则需要返回一个包含字段值的对象或元组。和Select()
没什么区别。
需要元组,因为它们已经实现了 IComparable。返回一个匿名对象会失败,因为它没有实现这个接口
【讨论】:
感谢您的帮助【参考方案4】:试试这个:
//Imagining your list like this :
var myList = new List<string>() "HP", "Canon", "Lexmark", "Samsung", "Other";
var other = myList.Where(ro => ro == "Other").FirstOrDefault();
myList.Remove(other);
var finalList = myList.OrderBy(ro => ro).ToList();
finalList.Add(other);
我希望这会有所帮助。
【讨论】:
修改原始数据在谈论排序时不是一个好主意 感谢您的帮助【参考方案5】:您也可以通过在 Order By 后面添加“Other”来做到这一点:
IEnumerable<string> lst = new string[]
"HP", "Canon", "Lexmark", "Samsung", "Other"
;
lst = lst.Select(x => x).Where(x => x != "Other").OrderBy(x => x).ToList();
lst = lst.Concat(new string[] "Other").ToList();
简而言之:
lst = lst.Select(x => x).Where(x => x != "Other").OrderBy(x => x).Concat(new string[] "Other").ToList();
【讨论】:
感谢您的帮助以上是关于如何订购 IEnumerable<T> 以使特殊项目始终位于底部? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何将多个 IEnumerable<IEnumerable<T>> 列表添加到 IEnumerable<List<int>>
如何判断 IEnumerable<T> 是不是需要延迟执行?
如何在 C# 中将 IEnumerable<T> 转换为 List<T>?