我有一个列表,我想从中选择第五个最高元素:
List<int> list = new List<int>();
list.Add(2);
list.Add(18);
list.Add(21);
list.Add(10);
list.Add(20);
list.Add(80);
list.Add(23);
list.Add(81);
list.Add(27);
list.Add(85);
但OrderbyDescending
不适用于此int
列表...
答案 0 :(得分:2)
int fifth = list.OrderByDescending(x => x).Skip(4).First();
答案 1 :(得分:1)
没有 LINQ 表达式:
int result;
if(list != null && list.Count >= 5)
{
list.Sort();
result = list[list.Count - 5];
}
else // define behavior when list is null OR has less than 5 elements
与LINQ表达式相比,它具有更好的性能,尽管我的第二个答案中提到的LINQ solutions是舒适和可靠的。
如果您需要极大的整数列表性能,我建议使用更专业的算法,例如Matthew Watson's answer。
注意:调用Sort()
方法时会修改列表。如果您不想这样,您必须使用列表的副本,如下所示:
List<int> copy = new List<int>(original);
List<int> copy = original.ToList();
答案 2 :(得分:1)
根据不超过5个元素的列表的严重性,您有2个选项。
如果列表永远不应该超过5,我会把它作为例外:
int fifth;
try
{
fifth = list.OrderByDescending(x => x).ElementAt(4);
}
catch (ArgumentOutOfRangeException)
{
//Handle the exception
}
如果您希望它少于5个元素,那么您可以将其保留为默认值并检查它。
int fifth = list.OrderByDescending(x => x).ElementAtOrDefault(4);
if (fifth == 0)
{
//handle default
}
这仍然是一些有缺陷的因为你可能最终得到第五个元素为0.这可以通过在linq之前将列表类型化为可空的int列表来解决:
var newList = list.Select(i => (int?)i).ToList();
int? fifth = newList.OrderByDescending(x => x).ElementAtOrDefault(4);
if (fifth == null)
{
//handle default
}
答案 3 :(得分:1)
最简单的方法是对数据进行排序并从前面获取N个项目。这是小数据集的推荐方法 - 任何更复杂的方法都是不值得的。
但是,对于大型数据集,可以更快地执行所谓的Partial Sort
。
有两种主要方法:使用堆,或使用专门的快速排序。
我链接的文章描述了如何使用堆。我将在下面提出一个部分内容:
public static IList<T> PartialSort<T>(IList<T> data, int k) where T : IComparable<T>
{
int start = 0;
int end = data.Count - 1;
while (end > start)
{
var index = partition(data, start, end);
var rank = index + 1;
if (rank >= k)
{
end = index - 1;
}
else if ((index - start) > (end - index))
{
quickSort(data, index + 1, end);
end = index - 1;
}
else
{
quickSort(data, start, index - 1);
start = index + 1;
}
}
return data;
}
static int partition<T>(IList<T> lst, int start, int end) where T : IComparable<T>
{
T x = lst[start];
int i = start;
for (int j = start + 1; j <= end; j++)
{
if (lst[j].CompareTo(x) < 0) // Or "> 0" to reverse sort order.
{
i = i + 1;
swap(lst, i, j);
}
}
swap(lst, start, i);
return i;
}
static void swap<T>(IList<T> lst, int p, int q)
{
T temp = lst[p];
lst[p] = lst[q];
lst[q] = temp;
}
static void quickSort<T>(IList<T> lst, int start, int end) where T : IComparable<T>
{
if (start >= end)
return;
int index = partition(lst, start, end);
quickSort(lst, start, index - 1);
quickSort(lst, index + 1, end);
}
然后,要访问列表中的第五大元素,您可以执行此操作:
PartialSort(list, 5);
Console.WriteLine(list[4]);
对于大型数据集,部分排序可能明显快于完整排序。
<强>附录强>
请参阅here了解使用QuickSelect algorithm的其他(可能更好)解决方案。
答案 4 :(得分:0)
LINQ 方法检索第5个最大元素 OR 引发异常 WHEN 列表为null或包含少于5个元素:
int fifth = list?.Count >= 5 ?
list.OrderByDescending(x => x).Take(5).Last() :
throw new Exception("list is null OR has not enough elements");
这个元素检索第五大元素 OR null
WHEN 列表为null
或包含少于5个元素:
int? fifth = list?.Count >= 5 ?
list.OrderByDescending(x => x).Take(5).Last() :
default(int?);
if(fifth == null) // define behavior
这个元素检索第5个最大元素 OR 最小元素 WHEN 列表包含少于5个元素:
if(list == null || list.Count <= 0)
throw new Exception("Unable to retrieve Nth biggest element");
int fifth = list.OrderByDescending(x => x).Take(5).Last();
所有这些解决方案都是可靠的,它们应该从不抛出“意外”的异常。
PS :我在这个答案中使用 .NET 4.7 。
答案 5 :(得分:0)
Here QuickSelect算法有一个C#实现,用于选择无序IList<>
中的第n个元素。
您必须将该页面中包含的所有代码放在static class
中,例如:
public static class QuickHelpers
{
// Put the code here
}
鉴于“库”(实际上是一个很大的代码块),那么你可以:
int resA = list.QuickSelect(2, (x, y) => Comparer<int>.Default.Compare(y, x));
int resB = list.QuickSelect(list.Count - 1 - 2);
现在......通常QuickSelect
会选择第n个最低元素。我们以两种方式扭转它:
对于resA
,我们基于默认的int
比较器创建反向比较器。我们通过反转Compare
方法的参数来做到这一点。请注意,索引是基于0的。所以有第0,第1,第2等等。
对于resB
,我们使用第0个元素是相反顺序的 list-1 元素的事实。所以我们从后面算。最高元素是有序列表中的list.Count - 1
,下一个list.Count - 1 - 1
,然后是list.Count - 1 - 2
,依此类推
理论上使用Quicksort应该比排序列表然后选择第n个元素更好,因为排序列表平均是O(NlogN)操作,然后选择第n个元素是O(1)操作,所以复合是O(NlogN)操作,而QuickSelect平均是O(N)操作。显然有一个但是。 O表示法没有显示k
因子...因此具有小k1的O(k1 * NlogN)可能比具有大k2的O(k2 * N)更好。只有多个现实生活中的基准可以告诉我们(你)什么是更好的,这取决于集合的大小。
关于算法的一个小注释:
与quicksort一样,quickselect通常作为就地算法实现,除了选择第k个元素之外,它还对数据进行部分排序。有关与排序的连接的进一步讨论,请参阅选择算法。
因此它修改了原始list
的排序。