如何从C#的列表中选择第二高的值?

时间:2018-12-19 20:16:49

标签: c# list

我有一个列表List<int> myList = new List<int>() { 10, 20, 8, 20, 9, 5, 20, 10 };,我想选择第二个最高值,在本例中为10。我编写了这段代码,它可以正常工作,但是我想知道是否有更短,更好的东西。

List<int> myList = new List<int>() { 10, 20, 8, 20, 9, 5, 20, 10 };
myList = myList.Distinct().ToList();
var descendingOrder = myList.OrderByDescending(i => i);
var sec = descendingOrder.Skip(1).First();

4 个答案:

答案 0 :(得分:9)

您可以停止使用中间变量和ToList()

var secondHighest = 
    myList
    .Distinct()
    .OrderByDescending(i => i);
    .Skip(1)
    .First();

这将与您的版本相同,但只需要一个语句,而不是三个。

我发现阅读代码清单要容易得多。

每个LINQ方法都在其自己的行上调用,并且没有中间变量,尤其是那些发生变化的中间变量(重新分配了myList,这使得它很难理解)。

答案 1 :(得分:7)

Dave's建议在一个管道中执行所有操作确实很好,因为它避免了:

  1. 不必要的中间变量
  2. 渴望在中间步骤创建新的集合对象
  3. 减少混乱。
  4. 更具可读性,即更容易看到正在发生的事情

另一方面,就效率而言,最好对源列表执行两次传递,而不是仅对第二个列表进行“排序”,而不是对整个列表进行“排序”。

var maximum = myList.Max();
var secondMaximum = myList.Where(x => x < maximum).Max();

答案 2 :(得分:0)

我认为我会避免使用LINQ,而只是使用一个标准的“循环遍历每个元素,如果电流高于最大值,则将current max推到第二位,将current value推到current max”

int sec = int.MinValue;
for(int i =0, m= int.MinValue; i <list.Length; i++)
  if(list[i] > m){
    sec = m;
    m = list[i];
  }

您给定的逻辑将这些值区分开,因此即使存在三个值为20的列表,看起来20也并不是列表中第二高的值。这可以通过>实现。如果我使用了> =,则每20个都会滚动变量,并且其行为就像无差别

如果您对性能感兴趣,请在一个包含几百万个条目的列表上进行测试,然后选择满足您对可读性与速度的需求的一个

答案 3 :(得分:0)

它不是LINQ-y,但它是O(N)并且易于阅读:

  public static int TheSecondMax()
  {
      List<int> myList = new List<int>() { 10, 20, 8, 20, 9, 5, 20, 10 };
      int max = int.MinValue;
      int secondMax = int.MinValue;
      foreach (var item in myList)
      {
          if (item > max)
          {
              max = item;
          }

          if (item > secondMax && item < max)
          {
              secondMax = item;
          }
      }

      return secondMax;
  }