Простой ответ:
Повреждение выходы цикл сразу.
Продолжаются , начинает обрабатывать следующий объект. (Если существует кто-либо путем перехода к строке оценки для/в то время как)
Вот простое * и относительно эффективное ** решение:
int indexMax
= !intList.Any() ? -1 :
intList
.Select( (value, index) => new { Value = value, Index = index } )
.Aggregate( (a, b) => (a.Value > b.Value) ? a : b )
.Index;
! IntList.Any ()? -1:
заставит -1
, если список пуст;
Select
будет проецировать каждый элемент int
в анонимный тип с два свойства: Значение
и Индекс
;
Агрегат
получит элемент с наивысшим значением
;
Наконец, мы получаем Индекс
выбранного элемента.
* Простота относительна. Цель здесь состояла в том, чтобы достичь баланса удобочитаемости и при этом сканировать список только один раз.
** Распределение большого количества новых объектов во время Select
, вероятно, расточительно. Как некоторые тестировали, он не работает для больших списков.
РЕДАКТИРОВАТЬ 1:
следующим образом:
var maxIndex = foo.IndexOf(foo.Max());
Я не могу улучшить ответ Джона Скита. в общем случае, поэтому я собираюсь получить приз «за высокую производительность» в конкретном случае списка целых чисел.
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;
}
Вот как это сделать в одной (длинной) строке с помощью 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;
}
}
Вот специальный метод 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;
}
}
Вот метод 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;
}
Это хотя бы один проход по списку.
Надеюсь, это поможет,
Кайл
Использование пользовательской функции, использование Max () и IndexOf () стоит дороже.