如何使用LINQ从一个有重复元素的列表中获取第N个最大元素?

3

我在StackOverflow的各种答案中看到,我可以通过类似以下方式来获取列表中第N个最大元素:

var nthFromTop = items.OrderByDescending().Skip(N-1).First();

但是如果列表中存在重复项,这个方法是否还能奏效呢?如果列表中有重复项,有没有方法可以使用LINQ获取第N大的元素(或一组元素)?如果不行,用C#最有效的方法是什么?


如果你有一个集合 {1,1,2,2,3,3,4,4},并将 N 设为 2,那么你期望的输出是什么?你想获取不同的值然后获取第 N 大的值吗?还是你想获取所有等于第 N 大的元素的集合? - Servy
抱歉表述不够清晰 - 理想情况下,我希望得到所有元素等于第N大的集合。 - ubuntunoob
那么所有发布的答案都是错误的。 - Servy
如果我获取了第N大的元素,那么我可以编写另一个查询以获取所有等于该元素的元素。有更好的方法吗? - ubuntunoob
是的,有的。我发了一个答案。 - Servy
4个回答

4
如果你想得到所有元素的集合,请使用 GroupBy。
 var items = new[] {1, 1, 2, 2, 3, 4, 4};
 var thirdLargest = items
   .GroupBy(x => x)
   .OrderByDescending(group => group.Key)
   .ElementAt(2);

根据提问者对问题的澄清,你的代码没有产生正确的输出。 - Servy
@Servy 我可能错了,但是ElementAt()方法为什么不能返回一个正确的组?当然,除了应该使用1而不是2作为参数之外。 - Tarec
1
@Tarec 如果 N2,则应该返回与第二大项相等的项目组。在您的示例输入中,第二大的项目是 4,因此它应该返回四个(第一组)的组合。 - Servy

2

要获取与第N大项相等的所有项集,您需要对项目进行分组,对分组进行排序,然后在N为正数时递减N组大小。当N达到零时,您已经找到包含第N大项的组。

public static IEnumerable<T> Foo<T>(this IEnumerable<T> source, int n)
{
    return source.GroupBy(x => x)
        .OrderByDescending(group => group.Key)
        .SkipWhile(group =>
        {
            n -= group.Count();
            return n > 0;
        })
        .First();
}

啊,你注意到了异常……:)这就是我在我的答案评论中所说的关于你放入你自己的异常的意思。 - terrybozzio

0

如果您想获取所有值,且存在重复值,则为第N大的值,请执行以下操作:

编辑

List<int> ints = new List<int>()
{
     1,2,5,8,12,34,12,52,34
};

int NthLargest = 1;
var queryresult = ints
                   .GroupBy(e => e)
                   .OrderByDescending(f => f.Count())
                   .ThenByDescending(k => k.Key)
                   .ElementAt(NthLargest - 1);

我现在明白了,刚才意识到了 OP 想要什么。然后在我的代码中(是的,我知道现在已经无关紧要了),只是将 orderbydescending f.Count() 放在了 f.Key 的位置。你确定在你的代码中 orderbydescending 中不想放入它吗? - terrybozzio
你的代码还是有问题,我非常确定我的代码是我想要的。他不想要第N大的组。他想要在序列中找到第N大的项目,包括重复的所有项目,然后找到与该项目相等的所有项目集。我的解决方案只需一次遍历即可执行功能等效操作。 - Servy
不是你的假设,而是 OP 想要的例子是这个序列 {1,2,2,2,2,3,12,12,34,34,34},第二大的数应该是序列 {34,34,34},如果不是这样的话,那么之前的代码就是正确的,会选择 {12,12}。 - terrybozzio
在你刚才给出的示例集中,第二大的项是34。有一个比它更大的项,那个项是34。等于34的项目集是{34, 34, 34},因此输出应该是这样的。所以,是的,当N为2时,该集合的输出确实是{34,34.34},但不是因为{34,34,34}是第二大的集合。那只是巧合。为了举一个更好的例子,给定集合{1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,4,5,5},其中N为3将返回{4},因为4是第三大的项,而{4}是所有等于4的项的集合。 - Servy
但它们不是4,而是5,这意味着您使用的算法不能产生正确的输出。我选择这个例子恰好是为了向您展示您的算法不起作用。按组大小排序是不正确的,因为要求中没有关于获取第N大组的内容。根本没有。它是关于获取与第N大个体项目相等的项目组。您的代码没有做到这一点,您的原始修订也没有。我的做到了。 - Servy
显示剩余6条评论

0
如果您想避免重复,为什么不使用group by呢?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接