2010-04-21 10 views
10

Al echar un vistazo a mi pregunta HERE, ahora quiero devolver el siguiente recomendación objeto (después) el que coincida con los criterios.LINQ Siguiente artículo en la lista

Digamos que encontré el elemento 6 de 10, me gustaría que la consulta devuelva el elemento 7 en su lugar.

¿O hay una manera mejor?

Respuesta

14

Puesto que usted tiene un objeto List<T> puede utilizar su método FindIndex en lugar de Where para obtener el índice del primer elemento coincidente en lugar del elemento en sí:

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

Una vez que tenga el índice que pueda obtener el siguiente artículo o artículo anterior o lo que quieras.

+0

+1 Para el uso de la sintaxis lambda. –

0

¿El artículo 7 coincide con su cláusula Where? Si es así, utilice los métodos de extensión y 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

No creo que esto funcione exactamente. En el caso de OPs parecería que el original solo devolvería 1 resultado, y quieren el siguiente en la lista ORIGINAL. –

+0

@spoulson, eso es correcto. Quiero encontrar el elemento correspondiente y luego devolver el siguiente elemento de la lista. – griegs

1

Este debería hacerlo. No he construido una prueba específicamente para eso.

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; 

Si necesita ambos registros, la instrucción de selección podría ser

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

Pero entonces tendría que hacer una agrupación para dar cuenta de un elemento coincidente ser el último elemento de la lista (no lo haría no ser un próximo artículo en ese caso).

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 }; 

El código que hice prueba fue algo similar con una lista de cadenas.

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; 

Cuál devuelve b, d y e.

28

Aquí está mi actual mejor método:

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

una respuesta anterior utiliza Skip(1).Take(1) que funciona, pero devuelve una lista de uno de los resultados. En mi caso (y tal vez en el caso del OP), estamos buscando el artículo real. Así que mi código se salta hasta que llega al que estamos buscando (un Where devolvería un subconjunto para que no tengamos acceso al siguiente elemento) luego omite uno más y luego obtiene el elemento.

+0

Nota: Esta respuesta se menciona en el curso de Microsoft Virtual Academy 'De-Mystifying LINQ' - Parte 6 –

4

¿Qué tal algo como esto:

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); 
    } 
} 

A continuación, puede llamarlo como si se tratara de dónde

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

Prueba este


siguiente elemento

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

ANTERIOR artículo nota: atrás() no funcionará para LINQ to SQL

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

Creo que 'Reverse' no está implementado en SQL Server. –

+0

http://msdn.microsoft.com/en-us/library/bb358497(v=vs.110).aspx Es LINQ y Reverse está aquí –

+0

Sí, es LINQ API, pero si es LINQ to SQL (Server) , lanzará un error, porque no hay equivalencia en SQL. –

Cuestiones relacionadas