Найти индекс значения в массиве

113

Можно ли каким-то образом использовать linq для поиска индекса значения в массиве?

Например, этот цикл находит индекс ключа в массиве.

for (int i = 0; i < words.Length; i++)
{
    if (words[i].IsKey)
    {
        keyIndex = i;
    }
}
initialZero
источник
На самом деле, было бы неплохо просто получить слово.
initialZero

Ответы:

183
int keyIndex = Array.FindIndex(words, w => w.IsKey);

Это фактически дает вам целочисленный индекс, а не объект, независимо от того, какой пользовательский класс вы создали.

Сидни Эндрюс
источник
1
Почему это не было сделано System.Linqпо умолчанию в качестве метода расширения ? Вот где все такое!
qJake
63

Для массивов вы можете использовать Array.FindIndex<T>:

int keyIndex = Array.FindIndex(words, w => w.IsKey);

Для списков вы можете использовать List<T>.FindIndex:

int keyIndex = words.FindIndex(w => w.IsKey);

Вы также можете написать общий метод расширения, который будет работать с любым Enumerable<T>:

///<summary>Finds the index of the first item matching an expression in an enumerable.</summary>
///<param name="items">The enumerable to search.</param>
///<param name="predicate">The expression to test the items against.</param>
///<returns>The index of the first matching item, or -1 if no items match.</returns>
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate) {
    if (items == null) throw new ArgumentNullException("items");
    if (predicate == null) throw new ArgumentNullException("predicate");

    int retVal = 0;
    foreach (var item in items) {
        if (predicate(item)) return retVal;
        retVal++;
    }
    return -1;
}

И вы также можете использовать LINQ:

int keyIndex = words
    .Select((v, i) => new {Word = v, Index = i})
    .FirstOrDefault(x => x.Word.IsKey)?.Index ?? -1;
Паоло Моретти
источник
2
Также существует метод List (T) .FindIndex
tdc
@Paolo, как насчет списка, созданного с помощью Lambda? Я получаю ошибку предиката.
Mihir Patel
10
int keyIndex = words.TakeWhile(w => !w.IsKey).Count();
Йонас Бётель
источник
3
+1 но что, если предмета не существует? получим 0, но индекс -1
Арсен Мкртчян
@ArsenMkrtchyan Если предмета не существует, появляются слова Длина
Джим Балтер
@ArsenMkrtchyan Вы написали "мы получим 0" ... это было неправильно. Вы написали «но индекс -1» ... это тоже неверно. -1 - обычный индикатор неудачи, но не единственно возможный. Подойдет любое значение вне 0..words.Length-1.
Джим Балтер,
1
@JimBalter, я имею в виду, что если элемент не существует, выражение вернет 0, что в нем не так? Я согласен с тем, что -1 - это общий индикатор, но согласен с тем, что очевидно, что в 99% случаев -1 - это ожидаемое значение, когда элемент не существует. по крайней мере 0 неверно, когда предмет не существует
Арсен Мкртчян
7

Если вы хотите найти слово, вы можете использовать

var word = words.Where(item => item.IsKey).First();

Это дает вам первый элемент, для которого IsKey истинно (если нет, вы можете использовать .FirstOrDefault()

Чтобы получить как элемент, так и индекс, вы можете использовать

KeyValuePair<WordType, int> word = words.Select((item, index) => new KeyValuePair<WordType, int>(item, index)).Where(item => item.Key.IsKey).First();
Гризли
источник
linq безумен. Я считал дженерики Java сумасшедшими. В любом случае, спасибо за помощь.
initialZero
Приведение возвращаемого значения - это общепринятая практика или есть способ определить тип слова?
initialZero
хорошо, я придумал это. DecodedMessageWord keyWord = words.Where (x => x.IsKey == true) .First <DecodedMessageWord> ();
initialZero
5
@initialZero проверьте перегрузки для First, это требует предиката, вам не нужен Where.
Юрий Факторович
3

Попробуй это...

var key = words.Where(x => x.IsKey == true);

источник
2
Это кажется очень слабым решением по сравнению с ответами Grizzly и masenkablast. masenkablast отвечает на исходный вопрос, а Grizzly дает лучшее решение для поиска слова, поскольку его последняя «var» будет фактическим словом, а не IEnumerable <TSource>, содержащим 1 слово.
Джеймс
2

Только что опубликовал мою реализацию метода расширения IndexWhere () (с модульными тестами):

http://snipplr.com/view/53625/linq-index-of-item--indexwhere/

Пример использования:

int index = myList.IndexWhere(item => item.Something == someOtherThing);
Joelsand
источник
Я бы не стал использовать эту библиотеку, она неправильно реализует эти методы. Он игнорирует утилизацию.
Юрий Факторович
1

Это решение помогло мне больше от msdn microsoft :

var result =  query.AsEnumerable().Select((x, index) =>
              new { index,x.Id,x.FirstName});

queryэто ваш toList()запрос.

Рошна Омер
источник
0
int index = -1;
index = words.Any (word => { index++; return word.IsKey; }) ? index : -1;
Марсель Вальдес Ороско
источник