如何订购 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&lt;string&gt; 正在传递给我,其中包含以下项目:

惠普 佳能 利盟 三星 其他

现在我想要实现的是按字母顺序排列项目,但我想将 other 项目保留在最后。我已经继续使用OrderBy(i =&gt; i)

其中列出的项目如下:

佳能 惠普 利盟 其他 三星

我想要的结果是

佳能 惠普 利盟 三星 其他

我尝试过使用.OrderBy(i =&gt; i != "Other").ThenBy(i =&gt; i),但这会将Other 项目放在顶部。

谁能告诉我如何实现这一点。

【问题讨论】:

【参考方案1】:

你必须使用OrderByDescending,因为truefalse“更高”

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&lt;T&gt; 或者(只是因为它稍微短一点)list.OrderBy(s =&gt; s == "Other").ThenBy(s =&gt; s); @Code 你不需要做任何事情。您可以将多个字段与OrderBy 一起使用,就像Select 一样。如果您在OrderBy 中使用返回(s=="Other",s)Tuple.Create(s=="Other",s) 的表达式,您将实现您想要的。相当于SQL的ORDER BY a,b,c @MatthewWatson 不短于 list.OrderBy(s=&gt;(s=="Other",s)),或 Tuple.Create 的等价物。我想知道性能差异会是什么。复制 vs 分配 vs(可能)多次迭代? 你的观点很好,我会坚持下去【参考方案2】:

我尝试过使用.OrderBy(i =&gt; i != "Other").ThenBy(i =&gt; i),但这会将其他项目放在顶部。

所以你快到了,你只需要颠倒你的第一个标准的排序顺序:将OrderBy替换为OrderByDesci != "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> 集合?

如何判断 IEnumerable<T> 是不是需要延迟执行?

如何在 C# 中将 IEnumerable<T> 转换为 List<T>?

如何将 IEnumerable<t> 或 IQueryable<t> 转换为 EntitySet<t>?

IEnumerable<T>.ToArray() 如何工作?