考虑到这是一个非常基本的任务,我无法想到一个合适的简单方法来完成它。您如何获得int数组中最小值的索引?使用Linq/MoreLinq是可能的。到目前为止,我还没有找到一个合理的一行代码。
既然你提到了 MoreLinq,那么如何考虑:
int[] array = ..
// Will throw if the array is empty.
// If there are duplicate minimum values, the one with the smaller
// index will be chosen.
int minIndex = array.AsSmartEnumerable()
.MinBy(entry => entry.Value)
.Index;
另一种选择:
// Will throw if the array is empty.
// Requires two passes over the array.
int minIndex = Array.IndexOf(array, array.Min());
当然可以编写自己的扩展方法:
// Returns last index of the value that is the minimum.
public static int IndexOfMin(this IEnumerable<int> source)
{
if(source == null)
throw new ArgumentNullException("source");
int minValue = int.MaxValue;
int minIndex = -1;
int index = -1;
foreach(int num in source)
{
index++;
if(num <= minValue)
{
minValue = num;
minIndex = index;
}
}
if(index == -1)
throw new InvalidOperationException("Sequence was empty");
return minIndex;
}
通过一些努力,您可以通过接受一个 IComparer<T>
(默认为 Comparer<T>.Default
)来将其推广到任何类型。
foreach
是迭代任意序列的正常方式。你可以获取枚举器然后使用 for
循环,但那看起来会很混乱。如果你真的需要枚举器,那么 while
循环更为常见。在这种情况下,两者都不必要。 - Anisource
想成了一个数组。 - mafuforeach
是经过优化的。它应该会产生与等效的for
循环相同的IL代码。 - Anifor(i=0;i<arr.Length;i++)a[i].Something();
进行数组边界检查的需求,这与C#编译器为数组上的foreach
生成的代码类似。 - AniLINQ可能不是解决这个问题的最佳方案,但下面是另一种O(n)的变体。它不进行排序,仅遍历数组一次。
var arr = new int[] { 3, 1, 0, 5 };
int pos = Enumerable.Range(0, arr.Length)
.Aggregate((a, b) => (arr[a] < arr[b]) ? a : b); // returns 2
更新: 直接回答原问题,我会这样做:
var arr = new int[] { 3, 1, 0, 5 };
int pos = 0;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] < arr[pos]) { pos = i; }
}
// pos == 2
不,它不使用LINQ。是的,它不止一行代码。但它非常简单且非常快速。将其制作成一个小方法,并从任何地方调用它,只需一行:pos = FindMinIndex(arr);
虽然不太友好于内存,但是...
array.Select((n, i) => new { index = i, value = n })
.OrderBy(item => item.value)
.First().index
虽然它看起来不太美观,但它只需要一次遍历序列,并且仅使用内置框架方法:
int index = yourArray.Select((x, i) => new { Val = x, Idx = i })
.Aggregate(new { Val = -1, Idx = -1 },
(a, x) => (x.Idx == 0 || x.Val < a.Val) ? x : a,
x => x.Idx);
当然,您可以编写一个通用的扩展方法:
int index = yourArray.MinIndex();
// ...
public static class EnumerableExtensions
{
public static int MinIndex<T>(
this IEnumerable<T> source, IComparer<T> comparer = null)
{
if (source == null)
throw new ArgumentNullException("source");
if (comparer == null)
comparer = Comparer<T>.Default;
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
return -1; // or maybe throw InvalidOperationException
int minIndex = 0;
T minValue = enumerator.Current;
int index = 0;
while (enumerator.MoveNext())
{
index++;
if (comparer.Compare(enumerator.Current, minValue) < 0)
{
minIndex = index;
minValue = enumerator.Current;
}
}
return minIndex;
}
}
}
int[] data = new []{ 10, 2, 3, 4, 2 };
var index = data
.Select((v, i) =>new {Index = i, Val = v})
.FirstOrDefault(v => v.Val == data.Min()).Index; // 1
但要小心,因为如果数组为空,你将会得到一个异常