Як отримати індекс елемента в списку за один крок?


193

Як я можу знайти індекс елемента в списку, не перебираючи його?

В даний час це виглядає не дуже приємно - пошук у списку одного і того ж продукту двічі, щоб отримати індекс:

var oProp = something;

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

Відповіді:


435

Як щодо методу List.FindIndex :

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

Цей метод виконує лінійний пошук; отже, цей метод є операцією O (n), де n - кількість.

Якщо елемент не буде знайдено, він поверне -1


2
Як щодо int index?
Ділан Ченскі

2
@DylanChensky він занадто багато
кодував

9
Для довідки, якщо елемент не знайдено; повернеться -1
Даніель Філіпе


71

EDIT: Якщо ви тільки з допомогою 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, але замість того , щоб повернутися на оригінальні деталі, він повернувся індекси тих елементів , які відповідали предиката.


Схоже, все, що він хоче - це індекс. Список <>. FindIndex (предикат <>) - найкращий підхід. Хоча заголовок питання інформує про інше, опис ОП досить зрозумілий, йому потрібен лише індекс "int theThingIActicallyAmInterestedIn"
Луї Річі

1
@LastCoder: Ага - пропустив FindIndex. Так, я повністю згоден.
Джон Скіт

Просто для того, щоб бути зрозумілим, чи "кращий" підхід "індекс / значення -> одинарний" (тут мається на увазі швидше в плані Big-O), ніж двічі вручну повторюватися? Або постачальник LINQ2Objects досить розумний, щоб оптимізувати одну з ітерацій? (Я роблю припущення, що і Select, і Single в цілому говорять про операції O (n))
Сара

1
@kai: Я думаю, вам потрібно почитати про те, як працює LINQ, в основному. Це занадто складно, щоб детально пояснити в коментарі. Однак ... це лише повторення над колекцією джерела. LINQ встановлює конвеєр, який ліниво перетворює вхідну послідовність в іншу послідовність, а потім Single()операція повторює цю послідовність і знаходить єдиний елемент, який відповідає предикату. Більш детально читайте мій серіал блогу edulinq
Джон Скіт

1
+1 мені було потрібно це рішення. Бос подумав, що я колись розумний. Мені рекомендували ретельно документувати це, оскільки він використовував анонімний тип і може бути незрозумілим для наступного кодера в цьому районі.
Адам Уеллс

14

Якщо ви не хочете використовувати LINQ, тоді:

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

таким чином ви повторюєте список лише один раз.


22
@KingKing ніхто не сказав, що це так.
Tomer W

1
Це та сама реалізація, що і Linq FindIndex?
Чашки

2
Мабуть, не той самий код, Список має деякі акуратні оптимізації тут і там. але мені важко повірити, що вони можуть шукати не упорядкований список менше ніж O (n), тому я б сказав, що вони, мабуть, дійсно схожі на практиці.
сара

6
  1. Просте рішення для пошуку індексу для будь-якого значення рядка у списку.

Ось код для списку рядків:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. Просте рішення для пошуку індексу для будь-якого значення Integer у Списку.

Ось код для списку цілих чисел:

    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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.