Получите индекс максимального элемента

Простой ответ:

Повреждение выходы цикл сразу.
Продолжаются , начинает обрабатывать следующий объект. (Если существует кто-либо путем перехода к строке оценки для/в то время как)

21
задан starsplusplus 8 December 2014 в 12:53
поделиться

7 ответов

Вот простое * и относительно эффективное ** решение:

int indexMax
    = !intList.Any() ? -1 :
    intList
    .Select( (value, index) => new { Value = value, Index = index } )
    .Aggregate( (a, b) => (a.Value > b.Value) ? a : b )
    .Index;
  1. ! IntList.Any ()? -1: заставит -1 , если список пуст;

  2. Select будет проецировать каждый элемент int в анонимный тип с два свойства: Значение и Индекс ;

  3. Агрегат получит элемент с наивысшим значением ;

  4. Наконец, мы получаем Индекс выбранного элемента.

* Простота относительна. Цель здесь состояла в том, чтобы достичь баланса удобочитаемости и при этом сканировать список только один раз.

** Распределение большого количества новых объектов во время Select , вероятно, расточительно. Как некоторые тестировали, он не работает для больших списков.

РЕДАКТИРОВАТЬ 1:

16
ответ дан 29 November 2019 в 06:18
поделиться

следующим образом:

var maxIndex = foo.IndexOf(foo.Max());
37
ответ дан 29 November 2019 в 06:18
поделиться

Я не могу улучшить ответ Джона Скита. в общем случае, поэтому я собираюсь получить приз «за высокую производительность» в конкретном случае списка целых чисел.

public static class Extensions
{
    public static int IndexOfMaximumElement(this IList<int> list)
    {
        int size = list.Count;

        if (size < 2)
            return size - 1;

        int maxValue = list[0];
        int maxIndex = 0;

        for (int i = 1; i < size; ++i)
        {
            int thisValue = list[i];
            if (thisValue > maxValue)
            {
                maxValue = thisValue;
                maxIndex = i;
            }
        }

        return maxIndex;
    }
3
ответ дан 29 November 2019 в 06:18
поделиться

Вот как это сделать в одной (длинной) строке с помощью LINQ, всего за один проход по коллекции. Он должен работать для любого IEnumerable , а не только для списков.

int maxIndex = intList
    .Select((x, i) => new { Value = x, Index = i })
    .Aggregate
        (
            new { Value = int.MinValue, Index = -1 },
            (a, x) => (a.Index < 0) || (x.Value > a.Value) ? x : a,
            a => a.Index
        );

Вот эквивалент вышеупомянутого не-LINQ, использующий цикл foreach . (Опять же, всего лишь один проход через коллекцию и должен работать для любого IEnumerable .)

int maxIndex = -1, maxValue = int.MinValue, i = 0;
foreach (int v in intList)
{
    if ((maxIndex < 0) || (v > maxValue))
    {
        maxValue = v;
        maxIndex = i;
    }
    i++;
}

Если вы знаете, что коллекция является IList , тогда простой цикл for , вероятно, является самым простым решением:

int maxIndex = -1, maxValue = int.MinValue;
for (int i = 0; i < intList.Count; i++)
{
    if ((maxIndex < 0) || (intList[i] > maxValue))
    {
        maxValue = intList[i];
        maxIndex = i;
    }
}
7
ответ дан 29 November 2019 в 06:18
поделиться

Вот специальный метод LINQ, который, как мне кажется, делает то, что вы хотите. (Раньше у меня был другой, который выполняет проекцию, но вы можете просто вызвать Select для этого, так как вам нужен только индекс.)

public static int MaxIndex<T>(this IEnumerable<T> source)
{
    IComparer<T> comparer = Comparer<T>.Default;
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            throw new InvalidOperationException("Empty sequence");
        }
        int maxIndex = 0;
        T maxElement = iterator.Current;
        int index = 0;
        while (iterator.MoveNext())
        {
            index++;
            T element = iterator.Current;
            if (comparer.Compare(element, maxElement) > 0)
            {
                maxElement = element;
                maxIndex = index;
            }
        }
        return maxIndex;
    }
}
12
ответ дан 29 November 2019 в 06:18
поделиться

Вот метод non-linq, если хотите:

private int ReturnMaxIdx(List<int> intList)
        {
            int MaxIDX = -1;
            int Max = -1;

            for (int i = 0; i < intList.Count; i++)
            {
                if (i == 0)
                {
                    Max = intList[0];
                    MaxIDX = 0;
                }
                else
                {
                    if (intList[i] > Max)
                    {
                        Max = intList[i];
                        MaxIDX = i;
                    }
                }
            }

            return MaxIDX;
        }

Это хотя бы один проход по списку.

Надеюсь, это поможет,

Кайл

2
ответ дан 29 November 2019 в 06:18
поделиться

Использование пользовательской функции, использование Max () и IndexOf () стоит дороже.

0
ответ дан 29 November 2019 в 06:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: