162

私はこれを書きました:

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();
    }
}

しかし、それがすでに存在するかどうかはわかりませんよね?

4

12 に答える 12

137

私は知恵に疑問を呈しますが、おそらく:

source.TakeWhile(x => x != value).Count();

(必要に応じEqualityComparer<T>.Defaultてエミュレートするために使用!=)-しかし、見つからない場合は-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;
}
于 2009-08-17T21:43:07.617 に答える
52

IEnumerable として取得することの要点は、コンテンツを遅延して反復できるようにすることです。そのため、実際にはインデックスの概念はありません。あなたがしていることは、IEnumerableにとってはあまり意味がありません。インデックスによるアクセスをサポートするものが必要な場合は、実際のリストまたはコレクションに入れます。

于 2009-08-17T21:48:25.907 に答える
28

私は次のように実装します:

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(x.a, value));
        return found == null ? -1 : found.i;
    }
}
于 2009-08-17T21:47:42.397 に答える
21

私が現在これを行っている方法は、すでに提案されている方法よりも少し短く、私が知る限り、望ましい結果が得られます:

 var index = haystack.ToList().IndexOf(needle);

少しぎこちないですが、十分に機能し、かなり簡潔です。

于 2014-11-06T11:29:10.543 に答える
10

最善のオプションは、次のように実装することだと思います。

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;
}

また、匿名オブジェクトは作成されません

于 2011-06-19T20:16:34.047 に答える
6

ゲームに少し遅れて、私は知っています...しかし、これは私が最近やったことです。それはあなたのものとは少し異なりますが、プログラマーは等値演算が必要なもの (述語) を指示することができます。<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;
 }

うまくいけば、これは誰かを助けます。

于 2014-12-19T23:39:41.443 に答える
5

数年後、これはLinqを使用し、見つからない場合は-1を返し、余分なオブジェクトを作成せず、見つかったときに短絡する必要があります[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);
}
于 2016-01-07T14:42:31.620 に答える
1

事後にインデックスを見つける代わりに、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);
}
于 2012-03-26T07:05:40.510 に答える