2010-04-21 2 views
10

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

Так сказать, я нашел пункт 6 из 10, я бы хотел, чтобы запрос возвращал пункт 7 вместо этого.

Или есть лучший способ?

ответ

14

Поскольку у вас есть List<T> объект, который вы можете использовать его метод FindIndex вместо Where, чтобы получить индекс первого совпадающего элемента, а не сам предмет:

int index = recommendations.FindIndex(rp => 
              rp.Products.Any(p => p.Product.Code == "A") 
             && rp.Products.Any(p => p.Product.Code == "B") 
            ); 

После того как вы индекс вы можете получить, что следующий элемент или предыдущий элемент или все, что вы хотите.

+0

+1 Для использования синтаксиса лямбда. –

0

Является ли пункт 7 в соответствии с вашим предложением Where? Если да, то использовать методы расширения Skip() и Take():

var myProducts = 
    from rp in recommendations 
    where 
     cp.Products.Any(p => p.Product.Code == "A") && 
     cp.Products.Any(p => p.Product.Code == "B") 
    select rp; 

var nextProduct = myProducts.Skip(1).Take(1); 
+0

Я не думаю, что это точно сработает. В случае OPs кажется, что оригинал вернет только 1 результат, и они захотят следующего в списке ORIGINAL. –

+0

@spoulson, это правильно. Я хочу найти соответствующий элемент, а затем вернуть следующий элемент в списке. – griegs

1

Этот должен сделать это. Я специально не тестировал его.

var nextProducts = from item1 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx }) 
        join item2 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx }) 
        on item1.Index equals item2.Index - 1 
        where item1.Rec.Products.Any(p => p.Code == "A") 
        && item1.Rec.Products.Any(p => p.Code == "B") 
        select item2.Rec; 

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

select new { MatchingItem = item1.Rec, NextItem = item2.Rec }; 

Но тогда вы должны сделать группировку, чтобы учесть для совпадающего элемента, являющегося последним пунктом в списке (там будет не будет следующим пунктом в этом случае).

var nextProducts = from item1 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx }) 
        join item2 in recommendations.Select((rec, idx) => new { Rec = rec, Index = idx }) 
        on item1.Index equals item2.Index - 1 
        into groupjoin 
        from i2 in groupjoin.DefaultIfEmpty() 
        where item1.Rec.Products.Any(p => p.Code == "A") 
        && item1.Rec.Products.Any(p => p.Code == "B") 
        select new { MatchingItem = item1.Rec, NextItem = i2 == null ? null : i2.Rec }; 

Код я сделал испытание было что-то подобное со списком строк.

List<string> list = new List<string>() { "a", "b", "c", "a", "d", "a", "e" }; 

var query = from item1 in list.Select((s, idx) => new { Item = s, Index = idx }) 
      join item2 in list.Select((s, idx) => new { Item = s, Index = idx }) 
      on item1.Index equals item2.Index - 1 
      where item1.Item == "a" 
      select item2.Item; 

Которые возвращают b, d и e.

28

Вот мой текущий лучший метод:

MyList.SkipWhile(item => item.Name != "someName").Skip(1).FirstOrDefault() 

Ранее ответ использует Skip(1).Take(1), который работает, но возвращает список одного результата. В моем случае (и, возможно, в случае с OP) мы ищем фактический элемент. Таким образом, мой код пропускается до тех пор, пока он не доберется до того, что мы ищем (a Where вернет подмножество, чтобы у нас не было доступа к следующему элементу), затем пропускает еще один, а затем получает элемент.

+0

Примечание: Этот ответ упоминается в курсе Microsoft Virtual Academy «De-Mystifying LINQ» - часть 6 –

4

Как о чем-то вроде этого:

public static class Extension 
{ 
    public static T Next<T>(this IEnumerable<T> source, Func<T, bool> predicate) 
    { 
     bool flag = false; 

     using (var enumerator = source.GetEnumerator()) 
     { 
      while (enumerator.MoveNext()) 
      { 
       if (flag) return enumerator.Current; 

       if(predicate(enumerator.Current)) 
       { 
        flag = true; 
       } 
      } 
     } 
     return default(T); 
    } 
} 

Вы могли бы назвать это, как вы бы для того, Где

Products.Next(x => x.Whatever); 
3

Попробуйте один


Следующий товар

MyList.SkipWhile(x => x != value).Skip(1).FirstOrDefault(); 

Предыдущий товар Примечание: Reverse() не будет работать для LINQ к SQL

var MyList2 = MyList.ToList(); 
MyList2.Reverse(); 
MyList2.SkipWhile(x => x != value).Skip(1).FirstOrDefault(); 
+0

Я думаю, что «Обратное» не реализовано в SQL Server. –

+0

http://msdn.microsoft.com/en-us/library/bb358497(v=vs.110).aspx Это LINQ и Reverse здесь –

+0

Да, это LINQ API, но если это LINQ to SQL (Server) , он будет вызывать ошибку, потому что в SQL нет эквивалентности. –

Смежные вопросы