シングルステップでリスト内のアイテムのインデックスを取得する方法


193

ループせずにリスト内のアイテムのインデックスを見つけるにはどうすればよいですか?

現在、これは非常に見栄えがよくありません-インデックスを取得するためだけに、同じアイテムのリストを2回検索します。

var oProp = something;

int theThingIActuallyAmInterestedIn = myList.IndexOf(myList.Single(i => i.Prop == oProp));

回答:


434

List.FindIndexメソッドはどうですか:

int index = myList.FindIndex(a => a.Prop == oProp);

このメソッドは線形検索を実行します。したがって、このメソッドはO(n)操作です。nはCountです。

アイテムが見つからない場合、-1を返します


2
いかがint indexですか?
Dylan Czenski 2016年

2
@DylanChensky彼はJSをコーディングしすぎています
lennyy

9
参考までに、アイテムが見つからない場合。-1が返されます
Daniel Filipe


71

編集:だけを使用しList<>ていて、インデックスのみが必要な場合List.FindIndexは、確かに最良のアプローチです。何か違うものが必要な人のために、ここではこの答えを残します(たとえば、の上にIEnumerable<>)。

Select述語でインデックスを取るのオーバーロードを使用して、リストを(インデックス、値)のペアに変換します。

var pair = myList.Select((Value, Index) => new { Value, Index })
                 .Single(p => p.Value.Prop == oProp);

次に:

Console.WriteLine("Index:{0}; Value: {1}", pair.Index, pair.Value);

または、インデックスのみが必要で、これを複数の場所で使用している場合、のような独自の拡張メソッドを簡単に作成できますがWhere、元のアイテムを返す代わりに、述語と一致するアイテムのインデックスを返しました。


彼が望んでいるのはインデックスだけのようです。List <>。FindIndex(Predicate <>)が最善のアプローチです。質問のタイトルはさもなければほのめかしますが、OPの説明は彼が "int theThingIActuallyAmInterestedIn"インデックスのみを必要とすることはかなり明確です
Louis Ricci

1
@LastCoder:Aha-FindIndexを逃していた。はい、完全に同意します。
Jon Skeet、2013

明確にするために、「インデックス/値->単一」のアプローチは、手動で2回繰り返すよりも「良い」(Big-Oに関しては高速であることを意味する)のでしょうか。または、LINQ2Objectsプロバイダーは、反復の1つを最適化するのに十分スマートですか?(私は、一般的に言えば、SelectとSingleの両方がO(n)操作であると仮定しています)
sara

1
@kai:LINQがどのように機能するかについて、基本的に読んでおく必要があると思います。コメントで詳しく説明するには複雑すぎます。ただし、これはソースコレクションに対して1回だけ繰り返されます。LINQはパイプラインをセットアップし、パイプラインは入力シーケンスを別のシーケンスに遅延変換します。その後、Single()操作はそのシーケンスを反復処理し、述語に一致する単一のアイテムを見つけます。詳細については、私のedulinqブログシリーズをご覧ください。codeblog.jonskeet.uk/ category
Jon Skeet

1
+1このソリューションが必要でした。上司は私が一度は賢いと思った。これは匿名の型を使用しており、その地域の次のコーダーには明確でない可能性があるため、注意深く文書化することをお勧めしました。
アダムウェルズ

14

LINQを使用しない場合は、次のようにします。

int index;
for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Prop == oProp)
    {
       index = i;
       break;
    }
}

この方法では、リストを1回だけ繰り返します。


22
@KingKing誰もがそうだと言った。
Tomer W 2013

1
これは対象FindIndex外のLinqと同じ実装ですか?
Coops

2
おそらく同じコードではなく、Listにはあちこちにいくつかのきちんとした最適化があります。しかし、順序付けられていないリストをO(n)未満で検索できるとは信じられないので、実際には、それらはおそらく本当に似ていると思います。
サラ

6
  1. リスト内の任意の文字列値のインデックスを見つける簡単なソリューション。

文字列のリストのコードは次のとおりです。

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. リスト内の整数値のインデックスを見つける簡単なソリューション。

整数リストのコードは次のとおりです。

    int indexOfNumber = myList.IndexOf(/*insert number from list*/);

2

IEnumerableのコピー/貼り付け可能な拡張メソッドは次のとおりです

public static class EnumerableExtensions
{
    /// <summary>
    /// Searches for an element that matches the conditions defined by the specified predicate,
    /// and returns the zero-based index of the first occurrence within the entire <see cref="IEnumerable{T}"/>.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="predicate">The predicate.</param>
    /// <returns>
    /// The zero-based index of the first occurrence of an element that matches the conditions defined by <paramref name="predicate"/>, if found; otherwise it'll throw.
    /// </returns>
    public static int FindIndex<T>(this IEnumerable<T> list, Func<T, bool> predicate)
    {
        var idx = list.Select((value, index) => new {value, index}).Where(x => predicate(x.value)).Select(x => x.index).First();
        return idx;
    }
}

楽しい。


2

誰かがArrayバージョンに不思議に思っている場合、それは次のようになります:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.