J'utilise .NET 3.5 et j'aimerais pouvoir obtenir chaque * n
* ème élément d'une liste. Je ne me soucie pas de savoir si cela est réalisé en utilisant une expression lambda ou LINQ.
Modifier
On dirait que cette question a provoqué pas mal de débats (ce qui est une bonne chose, non?). La principale chose que j'ai apprise est que, lorsque vous pensez connaître toutes les méthodes pour faire quelque chose (même aussi simple que cela), détrompez-vous!
return list.Where((x, i) => i % nStep == 0);
Je sais que c'est "old school", mais pourquoi ne pas simplement utiliser une boucle for avec stepping = n?
Cela ressemble à
IEnumerator<T> GetNth<T>(List<T> list, int n) {
for (int i=0; i<list.Count; i+=n)
yield return list[i]
}
ferait l'affaire. Je ne vois pas la nécessité d'utiliser Linq ou une expression lambda.
MODIFIER:
Fais-le
public static class MyListExtensions {
public static IEnumerable<T> GetNth<T>(this List<T> list, int n) {
for (int i=0; i<list.Count; i+=n)
yield return list[i];
}
}
et vous écrivez d'une manière LINQish
from var element in MyList.GetNth(10) select element;
2e édition :
Pour le rendre encore plus LINQish
from var i in Range(0, ((myList.Length-1)/n)+1) select list[n*i];
Vous pouvez utiliser la surcharge Where qui passe l'index avec l'élément
var everyFourth = list.Where((x,i) => i % 4 == 0);
Pour boucle
for(int i = 0; i < list.Count; i += n)
//Nth Item..
Je ne sais pas s'il est possible d'utiliser une expression LINQ, mais je sais que vous pouvez utiliser la méthode d'extension Where
pour le faire. Par exemple, pour obtenir chaque cinquième élément:
List<T> list = originalList.Where((t,i) => (i % 5) == 0).ToList();
Ce sera le premier article et chaque cinquième à partir de là. Si vous souhaitez commencer par le cinquième élément au lieu du premier, comparez avec 4 au lieu de comparer avec 0.
Je pense que si vous fournissez une extension linq, vous devriez pouvoir utiliser l'interface la moins spécifique, donc IEnumerable. Bien sûr, si vous êtes prêt pour la vitesse, en particulier pour les grands N, vous pouvez fournir une surcharge pour l'accès indexé. Ce dernier élimine le besoin de parcourir de grandes quantités de données inutiles et sera beaucoup plus rapide que la clause Where. Fournir les deux surcharges permet au compilateur de sélectionner la variante la plus appropriée.
public static class LinqExtensions
{
public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
{
if (n < 0)
throw new ArgumentOutOfRangeException("n");
if (n > 0)
{
int c = 0;
foreach (var e in list)
{
if (c % n == 0)
yield return e;
c++;
}
}
}
public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
{
if (n < 0)
throw new ArgumentOutOfRangeException("n");
if (n > 0)
for (int c = 0; c < list.Count; c += n)
yield return list[c];
}
}
A mon avis, pas de réponse, c'est bien. Toutes les solutions commencent à 0. Mais je veux avoir le nième élément réel
public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
{
for (int i = n - 1; i < list.Count; i += n)
yield return list[i];
}
@belucha J'aime ça, parce que le code client est très lisible et que le compilateur choisit l'implémentation la plus efficace. Je voudrais poursuivre sur cette lancée en réduisant les exigences à IReadOnlyList<T>
et en épargnant à la Division de disposer de LINQ hautes performances:
public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n) {
if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
int i = n;
foreach (var e in list) {
if (++i < n) { //save Division
continue;
}
i = 0;
yield return e;
}
}
public static IEnumerable<T> GetNth<T>(this IReadOnlyList<T> list, int n
, int offset = 0) { //use IReadOnlyList<T>
if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
for (var i = offset; i < list.Count; i += n) {
yield return list[i];
}
}