如何使用LINQ获取数组中最高值的索引?

时间:2022-11-27 17:24:09

I have an array of doubles and I want the index of the highest value. These are the solutions that I've come up with so far but I think that there must be a more elegant solution. Ideas?

我有一个双打数组,我想要最高值的索引。这些是我到目前为止提出的解决方案,但我认为必须有一个更优雅的解决方案。想法?

double[] score = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };
int topScoreIndex = score.Select((item, indx) => new {Item = item, Index = indx}).OrderByDescending(x => x.Item).Select(x => x.Index).First();

topScoreIndex = score.Select((item, indx) => new {Item = item, Index = indx}).OrderBy(x => x.Item).Select(x => x.Index).Last();

double maxVal = score.Max();
topScoreIndex = score.Select((item, indx) => new {Item = item, Index = indx}).Where(x => x.Item == maxVal).Select(x => x.Index).Single();

8 个解决方案

#1


39  

I suggest writing your own extension method (edited to be generic with an IComparable<T> constraint.)

我建议编写自己的扩展方法(编辑为通用IComparable 约束。)

public static int MaxIndex<T>(this IEnumerable<T> sequence)
    where T : IComparable<T>
{
    int maxIndex = -1;
    T maxValue = default(T); // Immediately overwritten anyway

    int index = 0;
    foreach (T value in sequence)
    {
        if (value.CompareTo(maxValue) > 0 || maxIndex == -1)
        {
             maxIndex = index;
             maxValue = value;
        }
        index++;
    }
    return maxIndex;
}

Note that this returns -1 if the sequence is empty.

请注意,如果序列为空,则返回-1。

A word on the characteristics:

关于特点的一句话:

  • This works with a sequence which can only be enumerated once - this can sometimes be very important, and is generally a desirable feature IMO.
  • 这适用于只能枚举一次的序列 - 这有时非常重要,并且通常是IMO的理想特征。
  • The memory complexity is O(1) (as opposed to O(n) for sorting)
  • 内存复杂度为O(1)(与排序的O(n)相反)
  • The runtime complexity is O(n) (as opposed to O(n log n) for sorting)
  • 运行时复杂度为O(n)(与排序的O(n log n)相反)

As for whether this "is LINQ" or not: if it had been included as one of the standard LINQ query operators, would you count it as LINQ? Does it feel particularly alien or unlike other LINQ operators? If MS were to include it in .NET 4.0 as a new operator, would it be LINQ?

至于这个“是否是LINQ”:如果它被列为标准LINQ查询运算符之一,你会把它算作LINQ吗?它感觉特别陌生或与其他LINQ运营商不同吗?如果MS将它作为​​新运算符包含在.NET 4.0中,它会是LINQ吗?

EDIT: If you're really, really hell-bent on using LINQ (rather than just getting an elegant solution) then here's one which is still O(n) and only evaluates the sequence once:

编辑:如果你真的,真的非常渴望使用LINQ(而不仅仅是获得一个优雅的解决方案),那么这里仍然是O(n)并且只评估序列一次:

int maxIndex = -1;
int index=0;
double maxValue = 0;

int urgh = sequence.Select(value => {
    if (maxIndex == -1 || value > maxValue)
    {
        maxIndex = index;
        maxValue = value;
    }
    index++;
    return maxIndex;
 }).Last();

It's hideous, and I don't suggest you use it at all - but it will work.

它很可怕,我建议你根本不使用它 - 但它会起作用。

#2


32  

Meh, why make it overcomplicated? This is the simplest way.

嗯,为什么要让它过于复杂?这是最简单的方法。

var indexAtMax = scores.ToList().IndexOf(scores.Max());

Yeah, you could make an extension method to use less memory, but unless you're dealing with huge arrays, you will never notice the difference.

是的,您可以使用扩展方法来使用更少的内存,但除非您处理大型数组,否则您将永远不会注意到差异。

#3


14  

var scoreList = score.ToList();
int topIndex =
    (
      from x
      in score
      orderby x
      select scoreList.IndexOf(x)
    ).Last();

If score wasn't an array this wouldn't be half bad...

如果得分不是数组,这不会是一半坏...

#4


4  

MoreLinq is a library that provides this functionality and much more.

MoreLinq是一个提供此功能的库。

#5


3  

I had this problem today (to get the index in a users array who had highest age), and I did on this way:

我今天遇到了这个问题(要获得年龄最大的用户数组中的索引),我这样做了:

var position = users.TakeWhile(u => u.Age != users.Max(x=>x.Age)).Count();

It was on C# class, so its noob solution, I´am sure your ones are better :)

这是在C#类,所以它的noob解决方案,我相信你的更好:)

#6


1  

This isn't the only Aggregate based solution, but this is really just a single line solution.

这不是唯一基于聚合的解决方案,但这实际上只是一个单线解决方案。

double[] score = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };

var max = score.Select((val,ix)=>new{val,ix}).Aggregate(new{val=-1.0,ix=-1},(z,last)=>z.val>last.val?z:last);

Console.WriteLine ("maximum value is {0}", max.val );
Console.WriteLine ("index of maximum value is {0}", max.ix );

#7


0  

The worst possible complexity of this is O(2N) ~= O(N), but it needs to enumerate the collection two times.

最糟糕的复杂性是O(2N)〜= O(N),但它需要枚举该集合两次。

 void Main()
{
    IEnumerable<int> numbers = new int[] { 1, 2, 3, 4, 5 };

    int max = numbers.Max ();
    int index = -1;
    numbers.Any (number => { index++; return number == max;  });

    if(index != 4) {
        throw new Exception("The result should have been 4, but " + index + " was found.");
    }

    "Simple test successful.".Dump();
}

#8


0  

If you want something that looks LINQy, in that it's purely functional, then Jon Skeets' answer above can be recast as:

如果你想看看LINQy的东西,因为它纯粹是功能性的,那么Jon Skeets上面的回答可以改写为:

public static int MaxIndex<T>(this IEnumerable<T> sequence) where T : IComparable<T>
    {
        return sequence.Aggregate(
            new { maxIndex = -1, maxValue = default(T), thisIndex = 0 },
            ((agg, value) => (value.CompareTo(agg.maxValue) > 0 || agg.maxIndex == -1) ?
                             new {maxIndex = agg.thisIndex, maxValue = value, thisIndex = agg.thisIndex + 1} :
                             new {maxIndex = agg.maxIndex, maxValue = agg.maxValue, thisIndex = agg.thisIndex + 1 })).
            maxIndex;
    }

This has the same computational complexity as the other answer, but is more profligate with memory, creating an intermediate answer for each element of the enumerable.

这与其他答案具有相同的计算复杂度,但是对于内存更加挥霍,为可枚举的每个元素创建中间答案。

#1


39  

I suggest writing your own extension method (edited to be generic with an IComparable<T> constraint.)

我建议编写自己的扩展方法(编辑为通用IComparable 约束。)

public static int MaxIndex<T>(this IEnumerable<T> sequence)
    where T : IComparable<T>
{
    int maxIndex = -1;
    T maxValue = default(T); // Immediately overwritten anyway

    int index = 0;
    foreach (T value in sequence)
    {
        if (value.CompareTo(maxValue) > 0 || maxIndex == -1)
        {
             maxIndex = index;
             maxValue = value;
        }
        index++;
    }
    return maxIndex;
}

Note that this returns -1 if the sequence is empty.

请注意,如果序列为空,则返回-1。

A word on the characteristics:

关于特点的一句话:

  • This works with a sequence which can only be enumerated once - this can sometimes be very important, and is generally a desirable feature IMO.
  • 这适用于只能枚举一次的序列 - 这有时非常重要,并且通常是IMO的理想特征。
  • The memory complexity is O(1) (as opposed to O(n) for sorting)
  • 内存复杂度为O(1)(与排序的O(n)相反)
  • The runtime complexity is O(n) (as opposed to O(n log n) for sorting)
  • 运行时复杂度为O(n)(与排序的O(n log n)相反)

As for whether this "is LINQ" or not: if it had been included as one of the standard LINQ query operators, would you count it as LINQ? Does it feel particularly alien or unlike other LINQ operators? If MS were to include it in .NET 4.0 as a new operator, would it be LINQ?

至于这个“是否是LINQ”:如果它被列为标准LINQ查询运算符之一,你会把它算作LINQ吗?它感觉特别陌生或与其他LINQ运营商不同吗?如果MS将它作为​​新运算符包含在.NET 4.0中,它会是LINQ吗?

EDIT: If you're really, really hell-bent on using LINQ (rather than just getting an elegant solution) then here's one which is still O(n) and only evaluates the sequence once:

编辑:如果你真的,真的非常渴望使用LINQ(而不仅仅是获得一个优雅的解决方案),那么这里仍然是O(n)并且只评估序列一次:

int maxIndex = -1;
int index=0;
double maxValue = 0;

int urgh = sequence.Select(value => {
    if (maxIndex == -1 || value > maxValue)
    {
        maxIndex = index;
        maxValue = value;
    }
    index++;
    return maxIndex;
 }).Last();

It's hideous, and I don't suggest you use it at all - but it will work.

它很可怕,我建议你根本不使用它 - 但它会起作用。

#2


32  

Meh, why make it overcomplicated? This is the simplest way.

嗯,为什么要让它过于复杂?这是最简单的方法。

var indexAtMax = scores.ToList().IndexOf(scores.Max());

Yeah, you could make an extension method to use less memory, but unless you're dealing with huge arrays, you will never notice the difference.

是的,您可以使用扩展方法来使用更少的内存,但除非您处理大型数组,否则您将永远不会注意到差异。

#3


14  

var scoreList = score.ToList();
int topIndex =
    (
      from x
      in score
      orderby x
      select scoreList.IndexOf(x)
    ).Last();

If score wasn't an array this wouldn't be half bad...

如果得分不是数组,这不会是一半坏...

#4


4  

MoreLinq is a library that provides this functionality and much more.

MoreLinq是一个提供此功能的库。

#5


3  

I had this problem today (to get the index in a users array who had highest age), and I did on this way:

我今天遇到了这个问题(要获得年龄最大的用户数组中的索引),我这样做了:

var position = users.TakeWhile(u => u.Age != users.Max(x=>x.Age)).Count();

It was on C# class, so its noob solution, I´am sure your ones are better :)

这是在C#类,所以它的noob解决方案,我相信你的更好:)

#6


1  

This isn't the only Aggregate based solution, but this is really just a single line solution.

这不是唯一基于聚合的解决方案,但这实际上只是一个单线解决方案。

double[] score = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };

var max = score.Select((val,ix)=>new{val,ix}).Aggregate(new{val=-1.0,ix=-1},(z,last)=>z.val>last.val?z:last);

Console.WriteLine ("maximum value is {0}", max.val );
Console.WriteLine ("index of maximum value is {0}", max.ix );

#7


0  

The worst possible complexity of this is O(2N) ~= O(N), but it needs to enumerate the collection two times.

最糟糕的复杂性是O(2N)〜= O(N),但它需要枚举该集合两次。

 void Main()
{
    IEnumerable<int> numbers = new int[] { 1, 2, 3, 4, 5 };

    int max = numbers.Max ();
    int index = -1;
    numbers.Any (number => { index++; return number == max;  });

    if(index != 4) {
        throw new Exception("The result should have been 4, but " + index + " was found.");
    }

    "Simple test successful.".Dump();
}

#8


0  

If you want something that looks LINQy, in that it's purely functional, then Jon Skeets' answer above can be recast as:

如果你想看看LINQy的东西,因为它纯粹是功能性的,那么Jon Skeets上面的回答可以改写为:

public static int MaxIndex<T>(this IEnumerable<T> sequence) where T : IComparable<T>
    {
        return sequence.Aggregate(
            new { maxIndex = -1, maxValue = default(T), thisIndex = 0 },
            ((agg, value) => (value.CompareTo(agg.maxValue) > 0 || agg.maxIndex == -1) ?
                             new {maxIndex = agg.thisIndex, maxValue = value, thisIndex = agg.thisIndex + 1} :
                             new {maxIndex = agg.maxIndex, maxValue = agg.maxValue, thisIndex = agg.thisIndex + 1 })).
            maxIndex;
    }

This has the same computational complexity as the other answer, but is more profligate with memory, creating an intermediate answer for each element of the enumerable.

这与其他答案具有相同的计算复杂度,但是对于内存更加挥霍,为可枚举的每个元素创建中间答案。