2010-11-02 10 views
29
var item = list.Where(t => somecondition); 

Мне очень хотелось бы узнать индекс возвращаемого элемента, на самом деле, в моем случае все, что я хочу, это индекс, так что Я могу .Skip() в списке.Поиск первого индекса элемента, который соответствует условию с использованием LINQ

Есть ли способ сделать это в IEnumerable? Я не хотел бы использовать List<T> для этого, но это есть метод FindIndex()

ответ

22

мне нужно больше контекста, но если вы только индекс, так что вы можете позвонить .Skip, я рекомендовал бы взглянуть на .SkipWhile ,

Если вам действительно нужен указатель, я бы предложил написать собственный метод расширения .IndexOf.

+0

+1 за то, что он, вероятно, хочет использовать 'SkipWhile', потому что поиск индекса, а затем вызов' Skip' дважды перечисляет запрос – Gabe

+0

Так близко ... теперь я хочу использовать SkipWhile в сочетании с счетчиком, то есть списком. SkipWhile (myBusinessLogicCondition && list.Count - SkipIndex> someXnumber); – user494352

+0

user494352: Кажется, что вы хотите посмотреть на список Jon.Select(). SkipWhile() 'ответ в конце своего сообщения. – Gabe

6

Вы можете проецировать элементы списка с их индексами первых:

var item = list.Select((item, index) => new { Item = item, Index = index }) 
       .Where(pair => SomeCondition(pair.Item)) 
       .Select(result => result.Index); 
36

Конечно, это довольно легко:

var index = list.Select((value, index) => new { value, index = index + 1 }) 
       .Where(pair => SomeCondition(pair.value)) 
       .Select(pair => pair.index) 
       .FirstOrDefault() - 1; 

Это вернет индекс, если он найдет что-то подходящее, или -1 в противном случае. +1 и -1 - это поведение для случая, когда совпадений нет. Если бы вы знали, что всегда будет матч, было бы проще:

var index = list.Select((value, index) => new { value, index }) 
       .Where(pair => SomeCondition(pair.value)) 
       .Select(pair => pair.index) 
       .FirstOrDefault(); 

Если вы счастливы, чтобы получить остальную часть списка с этого момента и далее, SkipWhile, безусловно, ваш друг, как уже упоминалось, Chris , Если хотят, остальную часть списка и оригинального индекс, это тоже легко:

var query = list.Select((value, index) => new { value, index }) 
       .SkipWhile(pair => !SomeCondition(pair.value)) 

Это даст вам последовательность { value, index } пара из первого значения, соответствующего SomeCondition.

+1

Это позор, что 'FirstOrDefault' не позволяет задать значение по умолчанию, а? – Gabe

+0

@Gabe: Да :(По общему признанию, было бы легко написать собственную реализацию ... –

+0

Спасибо, Джон, я пытаюсь включить SkipWhile с индексом, скорее всего, считаю, что я пропустил слишком много. – user494352

14

Ofcourse его можно с помощью IEnumerable ...

public static class EnumerableExtension 
    { 

     public static int FirstIndexMatch<TItem>(this IEnumerable<TItem> items, Func<TItem,bool> matchCondition) 
     { 
      var index = 0; 
      foreach (var item in items) 
      { 
       if(matchCondition.Invoke(item)) 
       { 
        return index; 
       } 
       index++; 
      } 
      return -1; 
     } 
    } 
+1

+1. Я обычно предпочитаю больше ответов linq-y, таких как Jon's, но в этом случае это решение гораздо проще смотреть и понимать, что он делает. И как метод расширения он все еще может быть * использован * в выражении linq. Беспроигрышная. –

+0

Использование 'matchCondition.Invoke (item)' не требуется. Вы можете просто выполнить matchCondition (item) '. – ErikE

24

Если вы действительно просто нужен первый индекс, то считать те, которые не соответствуют:

var index = list.TakeWhile(t => !someCondition).Count() 
Смежные вопросы