2010-08-25 11 views

Respuesta

23

Sólo descubierto a mí mismo ...

El método IEnumerable<T>.Where() tiene una sobrecarga que toma el índice del elemento actual - justo lo que recetó el doctor.

(new []{1,2,3,4,5}).Where((elem, idx) => idx % 2 == 0); 

Esto volvería

{1, 3, 5} 

Actualización: Con el fin de cubrir tanto mi caso de uso y la sugerencia de Dan Tao, también vamos a especificar lo que debe ser el primer elemento devuelto:

var firstIdx = 1; 
var takeEvery = 2; 
var list = new []{1,2,3,4,5}; 

var newList = list 
    .Skip(firstIdx) 
    .Where((elem, idx) => idx % takeEvery == 0); 

... devolvería

{2, 4} 
+2

Primera vez que he visto un uso realmente sólido para el índice en un predicado de colección, bravo, no lo hubiera pensado. –

+0

Puede definir un método de extensión que devuelva esto. Donde (...) para que esto quede más claro en su aplicación. – Douglas

+5

Podría sugerir el uso de 'idx + 1' para que coincida con la descripción de" cada elemento enésimo "; al menos para mí, esto sugiere que el primer elemento devuelto debería ser el enésimo elemento. Entonces, cada segundo elemento en '{1,2,3,4,5}' - a * me * - significa '{2,4}' (tu código devuelve '{1,3,5}'). Quizás esto es subjetivo, sin embargo. –

8

Para implementar Cristi's suggestion:

public static IEnumerable<T> Sample<T>(this IEnumerable<T> source, int interval) 
{ 
    // null check, out of range check go here 

    return source.Where((value, index) => (index + 1) % interval == 0); 
} 

Uso:

var upToTen = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 

var evens = upToTen.Sample(2); 
var multiplesOfThree = upToTen.Sample(3); 
+0

También podría saltear la matriz y usar 'Enumerable.Range (1,10)'. –

+2

@Anthony: es solo un ejemplo, destinado a la comprensión inmediata. Sé que algunos desarrolladores tendrían que buscar 'Enumerable.Range'. –

0

Aunque no LINQ también puede crear un método de extensión con yield.

public static IEnumerable<T> EverySecondObject<T>(this IEnumerable<T> list) 
{ 
    using (var enumerator = list.GetEnumerator()) 
    { 
     while (true) 
     { 
      if (!enumerator.MoveNext()) 
       yield break; 
      if (enumerator.MoveNext()) 
       yield return enumerator.Current; 
      else 
       yield break; 
     } 
    } 
} 
+2

¡Envuelve eso en un 'uso'! ('IEnumerable' hereda' IDisposable'.) –

+0

@Dan: Quiere decir IEnumerator. ¿Cómo es que nunca me había dado cuenta de eso antes?

+0

Sí, quise decir 'IEnumerator'. ¡Ups! (Por algún motivo siempre escribo uno cuando me refiero a escribir el otro. Debe ser memoria muscular) –

Cuestiones relacionadas