如何获得IEnumerable中的元素的索引?
我写了这个:
public static class EnumerableExtensions { public static int IndexOf<T>(this IEnumerable<T> obj, T value) { return obj .Select((a, i) => (a.Equals(value)) ? i : -1) .Max(); } public static int IndexOf<T>(this IEnumerable<T> obj, T value , IEqualityComparer<T> comparer) { return obj .Select((a, i) => (comparer.Equals(a, value)) ? i : -1) .Max(); } }
但是我不知道它是否已经存在,是吗?
IEnumerable让事情变得完整的一点是,你可以懒洋洋地遍历内容。 因此,没有真正的索引概念。 你所做的事情对于IEnumerable来说确实没什么意义。 如果你需要一些支持索引访问的东西,把它放在一个实际的列表或集合中。
我会质疑智慧,但也许:
source.TakeWhile(x => x != value).Count();
(使用EqualityComparer<T>.Default
模拟!=
如果需要的话) – 但是如果没有find,你需要注意返回-1 …所以也许只是做了很长的路要走
public static int IndexOf<T>(this IEnumerable<T> source, T value) { int index = 0; var comparer = EqualityComparer<T>.Default; // or pass in as a parameter foreach (T item in source) { if (comparer.Equals(item, value)) return index; index++; } return -1; }
我会这样实现它:
public static class EnumerableExtensions { public static int IndexOf<T>(this IEnumerable<T> obj, T value) { return obj.IndexOf(value, null); } public static int IndexOf<T>(this IEnumerable<T> obj, T value, IEqualityComparer<T> comparer) { comparer = comparer ?? EqualityComparer<T>.Default; var found = obj .Select((a, i) => new { a, i }) .FirstOrDefault(x => comparer.Equals(xa, value)); return found == null ? -1 : found.i; } }
我现在这样做的方式比已经build议的要短一些,据我所知,可以给出所需的结果:
var index = haystack.ToList().IndexOf(needle);
这有点笨重,但它的工作很简单。
我认为最好的select是像这样实施:
public static int IndexOf<T>(this IEnumerable<T> enumerable, T element, IEqualityComparer<T> comparer = null) { int i = 0; comparer = comparer ?? EqualityComparer<T>.Default; foreach (var currentElement in enumerable) { if (comparer.Equals(currentElement, element)) { return i; } i++; } return -1; }
它也不会创build匿名对象
游戏有点晚了,我知道…但是这是我最近做的。 它与你的稍有不同,但允许程序员指定相等操作需要的是什么(谓词)。 在处理不同的types时,我发现它非常有用,因为不pipe对象types和构build在等号运算符中的<T>
如何,我都有一个通用的方法。
它也有一个非常非常小的内存占用,是非常,非常快速/高效率…如果你在乎这一点。
更糟糕的是,您只需将其添加到您的扩展名列表中即可。
无论如何…在这里。
public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate) { int retval = -1; var enumerator = source.GetEnumerator(); while (enumerator.MoveNext()) { retval += 1; if (predicate(enumerator.Current)) { IDisposable disposable = enumerator as System.IDisposable; if (disposable != null) disposable.Dispose(); return retval; } } IDisposable disposable = enumerator as System.IDisposable; if (disposable != null) disposable.Dispose(); return -1; }
希望这有助于某人。
几年后,但是这使用Linq,如果没有find,返回-1,不会创build额外的对象,并应发现短路[而不是迭代整个IEnumerable]:
public static int IndexOf<T>(this IEnumerable<T> list, T item) { return list.Select((x, index) => EqualityComparer<T>.Default.Equals(item, x) ? index : -1) .FirstOr(x => x != -1, -1); }
“FirstOr”在哪里:
public static T FirstOr<T>(this IEnumerable<T> source, T alternate) { return source.DefaultIfEmpty(alternate) .First(); } public static T FirstOr<T>(this IEnumerable<T> source, Func<T, bool> predicate, T alternate) { return source.Where(predicate) .FirstOr(alternate); }
捕捉位置的最佳方法是通过FindIndex
此函数仅适用于List<>
例
int id = listMyObject.FindIndex(x => x.Id == 15);
如果你有枚举或数组使用这种方式
int id = myEnumerator.ToList().FindIndex(x => x.Id == 15);
要么
int id = myArray.ToList().FindIndex(x => x.Id == 15);
在事实之后find索引的另一种方法是包装Enumerable,有点类似于使用Linq GroupBy()方法。
public static class IndexedEnumerable { public static IndexedEnumerable<T> ToIndexed<T>(this IEnumerable<T> items) { return IndexedEnumerable<T>.Create(items); } } public class IndexedEnumerable<T> : IEnumerable<IndexedEnumerable<T>.IndexedItem> { private readonly IEnumerable<IndexedItem> _items; public IndexedEnumerable(IEnumerable<IndexedItem> items) { _items = items; } public class IndexedItem { public IndexedItem(int index, T value) { Index = index; Value = value; } public T Value { get; private set; } public int Index { get; private set; } } public static IndexedEnumerable<T> Create(IEnumerable<T> items) { return new IndexedEnumerable<T>(items.Select((item, index) => new IndexedItem(index, item))); } public IEnumerator<IndexedItem> GetEnumerator() { return _items.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
其中给出了一个用例:
var items = new[] {1, 2, 3}; var indexedItems = items.ToIndexed(); foreach (var item in indexedItems) { Console.WriteLine("items[{0}] = {1}", item.Index, item.Value); }