web-dev-qa-db-fra.com

Comment puis-je obtenir le nième élément d'une liste <T>?

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!

97
Paul Suart
return list.Where((x, i) => i % nStep == 0);
169
mquander

Je sais que c'est "old school", mais pourquoi ne pas simplement utiliser une boucle for avec stepping = n?

36
Michael Todd

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];
33
MartinStettner

Vous pouvez utiliser la surcharge Where qui passe l'index avec l'élément

var everyFourth = list.Where((x,i) => i % 4 == 0);
25
JaredPar

Pour boucle 

for(int i = 0; i < list.Count; i += n)
    //Nth Item..
10
Quintin Robinson

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.

3
Guffa

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];
    }
}
2
belucha

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];
}
0
user2340145
private static readonly string[] sequence = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15".Split(',');

static void Main(string[] args)
{
    var every4thElement = sequence
      .Where((p, index) => index % 4 == 0);

    foreach (string p in every4thElement)
    {
        Console.WriteLine("{0}", p);
    }

    Console.ReadKey();
}

sortie

 enter image description here

0
Anwar Ul Haq

@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];
        }
    }
0
Spoc