如何获取IEnumerable中元素的索引?

177
我写了这个:
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();
    }
}

但是我不知道它是否已经存在,它存在吗?

5
Max方法的问题在于:a:它会继续查找,b:当存在重复项时返回最后一个索引(人们通常希望是第一个索引)。请注意不改变原意并使翻译通俗易懂。 - Marc Gravell
4
geekswithblogs.net网站上,比较了4种解决方案及其性能。其中ToList()/FindIndex()技巧表现最佳。 - nixda
@nixda 那个链接不起作用。但ToList()听起来不是最有效的解决方案。Marc Graveli的那个会在找到匹配项时停止。 - KevinVictor
1
@KevinVictor 你仍然可以通过web.archive.org查看它。 - nixda
哦,有趣...如果真的是这样的话,那会改变最佳答案是什么,希望有人可以验证一下。 - KevinVictor
也许这取决于实现IEnumerable接口的底层对象是什么。 - KevinVictor
12个回答

0
这个可以通过一个扩展(作为代理)变得非常酷,例如:
collection.SelectWithIndex(); 
// vs. 
collection.Select((item, index) => item);

这将自动为可通过此Index属性访问的集合分配索引。

接口:

public interface IIndexable
{
    int Index { get; set; }
}

自定义扩展(可能最适用于与EF和DbContext一起使用):

public static class EnumerableXtensions
{
    public static IEnumerable<TModel> SelectWithIndex<TModel>(
        this IEnumerable<TModel> collection) where TModel : class, IIndexable
    {
        return collection.Select((item, index) =>
        {
            item.Index = index;
            return item;
        });
    }
}

public class SomeModelDTO : IIndexable
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    public int Index { get; set; }
}

// In a method
var items = from a in db.SomeTable
            where a.Id == someValue
            select new SomeModelDTO
            {
                Id = a.Id,
                Name = a.Name,
                Price = a.Price
            };

return items.SelectWithIndex()
            .OrderBy(m => m.Name)
            .Skip(pageStart)
            .Take(pageSize)
            .ToList();

-1

试试这个:

static int FindIndex<T>(this IEnumerable<T> a, Predicate<T> f) =>
    a.TakeWhile(x => !f(x)).Count();

static int IndexOf<T>(this IEnumerable<T> a, T value) =>
    a.FindIndex(x => EqualityComparer<T>.Default.Equals(x, value));

var i = new[] { 1, 2, 3 }.IndexOf(2); // 1

这只是重新排列了2009年此答案中所说的部分内容。 - Gert Arnold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接