2010-08-25 2 views

Répondre

23

Juste pensé à elle ... moi

La méthode IEnumerable<T>.Where() a une surcharge qui prend l'indice de l'élément courant - exactement ce que le médecin a ordonné.

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

Ce retournerait

{1, 3, 5} 

Mise à jour: Afin de couvrir à la fois mon cas d'utilisation et la suggestion de Dan Tao, Précisons aussi ce que le premier élément retourné doit être:

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

... reviendrait

{2, 4} 
+2

Première fois que j'ai vu une utilisation vraiment solide pour l'index dans un prédicat de collection, bravo, je n'aurais pas pensé à ça. –

+0

Vous pouvez définir une méthode d'extension qui renvoie this.Where (...) pour le rendre plus clair dans votre application elle-même. – Douglas

+5

Je pourrais suggérer d'utiliser 'idx + 1' pour correspondre à la description de" chaque Nième élément "; au moins pour moi, cela suggère que le premier élément renvoyé devrait être le Nième élément. Donc, tous les deuxièmes éléments dans '{1,2,3,4,5}' - to * me * - signifient '{2,4}' (votre code renvoie '{1,3,5}'). Peut-être que c'est subjectif, cependant. –

8

Pour mettre en œuvre 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); 
} 

Utilisation:

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

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

Vous pouvez également passer le tableau et utiliser 'Enumerable.Range (1,10)'. –

+2

@Anthony: C'est juste un exemple, destiné à la compréhension immédiate. Je sais que certains développeurs devraient rechercher 'Enumerable.Range'. –

0

Sans LINQ, vous pouvez également créer une méthode d'extension avec 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

Envelopper dans un 'using'! ('IEnumerable' hérite de' IDisposable'.) –

+0

@Dan: Vous voulez dire IEnumerator. Comment se fait-il que je n'ai jamais réalisé cela auparavant?

+0

Oui, je voulais dire 'IEnumerator'. Oups! (Pour une raison quelconque, je tape toujours un quand je veux taper l'autre .. Doit être de la mémoire musculaire.) –

Questions connexes