Comment obtenir les premiers N éléments d'une liste en C #?


384

Je voudrais utiliser Linq pour interroger un horaire de bus dans mon projet, afin que je puisse à tout moment obtenir les 5 prochaines heures d'arrivée du bus. Comment puis-je limiter ma requête aux 5 premiers résultats?

Plus généralement, comment puis-je prendre une tranche d'une liste en C #? (En Python, j'utiliserais mylist[:5]pour obtenir les 5 premiers éléments.)

Réponses:


709
var firstFiveItems = myList.Take(5);

Ou pour trancher:

var secondFiveItems = myList.Skip(5).Take(5);

Et bien sûr, il est souvent pratique d'obtenir les cinq premiers articles selon une sorte de commande:

var firstFiveArrivals = myList.OrderBy(i => i.ArrivalTime).Take(5);

87
Lève-t-il une exception s'il n'y a, par exemple, que 3 éléments dans la liste? Ou en faudra-t-il autant qu'il y en a jusqu'à 5?
bobek

87
@bobek: Il ne lève pas d'exception. Il retourne simplement ce qu'il a s'il n'y a pas assez d'éléments.
Joshua Pech

1
exactement, aucune exception levée Skip and Take combiné a résolu mon problème car je voulais prendre n'importe quelle collection générique et traiter x éléments par lot
JohanLarsson

Il convient de noter que .Take(n)renvoie un TakeIterator; il ne renvoie pas de liste contenant des néléments (en supposant que beaucoup sont disponibles). Utilisez .ToArray()ou .ToList()sur le résultat de Takepour obtenir un tableau ou une liste concret.
Andrew Webb

69

Au cas où quelqu'un serait intéressé (même si la question ne demande pas cette version), en C # 2 serait: (j'ai édité la réponse, suite à quelques suggestions)

myList.Sort(CLASS_FOR_COMPARER);
List<string> fiveElements = myList.GetRange(0, 5);

Peut-être ajouter également un prédicat anonyme?
AlexeyMK

2
List <T> .Sort renvoie void; vous devez trier, puis utiliser GetRange séparément. Vous pouvez également utiliser une méthode anonyme Comparaison <T> pour supprimer le besoin de CLASS_FOR_COMPARER.
Marc Gravell

@AlexeyMK - vous voulez dire une comparaison <T>, pas un prédicat (Predicate <T>) - un prédicat est utilisé pour filtrer les données
Marc Gravell

Je crois que cette réponse est utile même maintenant, 10 ans et de nombreuses versions C # plus tard. Pour le cas spécifique où vous avez une liste. Surtout si vous sautez de nombreux éléments. Par exemple, vous avez une liste d'un million d'articles, et vous voulez une tranche de 5 d'entre eux, loin dans la liste. GetRange sait exactement où aller pour les récupérer. Je ne sais pas si Skip+ Takeest aussi intelligent ou s'il énumère les éléments ignorés. Et je n'ai pas besoin de savoir - j'utilise simplement GetRange (quand on me donne une liste). Assurez-vous simplement que le deuxième paramètre est le nombre (plutôt que le dernier index ).
ToolmakerSteve

Ce qui est bien, .Take(n)c'est que vous n'avez pas à vous inquiéter s'il y a moins de néléments dans la séquence sur laquelle il fonctionne. Le problème List<T>.GetRange(0, count)est que vous devez vous inquiéter ... vous obtiendrez un ArgumentExceptions'il n'y a pas d' countarticles.
Andrew Webb

5

Comme paginationvous pouvez utiliser la formule ci-dessous pour prendre slice of list or elements:

var slice = myList.Skip((pageNumber - 1) * pageSize)
                  .Take(pageSize);

Exemple 1: cinq premiers éléments

var pageNumber = 1;
var pageSize = 5;

Exemple 2: deuxièmes cinq éléments

var pageNumber = 2;
var pageSize = 5;

Exemple 3: troisièmes cinq éléments

var pageNumber = 3;
var pageSize = 5;

Si vous remarquez des paramètres de formule pageSize = 5et pageNumberque vous changez, si vous voulez changer le nombre d'articles en tranches, vous changez pageSize.


1

Pour prendre les 5 premiers éléments, utilisez une expression comme celle-ci:

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

ou

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

Il sera plus rapide que la variante orderBy, car le moteur LINQ n'analysera pas toutes les listes en raison de l'exécution retardée et ne triera pas tous les tableaux.

class MyList : IEnumerable<int>
{

    int maxCount = 0;

    public int RequestCount
    {
        get;
        private set;
    }
    public MyList(int maxCount)
    {
        this.maxCount = maxCount;
    }
    public void Reset()
    {
        RequestCount = 0;
    }
    #region IEnumerable<int> Members

    public IEnumerator<int> GetEnumerator()
    {
        int i = 0;
        while (i < maxCount)
        {
            RequestCount++;
            yield return i++;
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion
}
class Program
{
    static void Main(string[] args)
    {
        var list = new MyList(15);
        list.Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 5;

        list.Reset();
        list.OrderBy(q => q).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 15;

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
    }
}

25
Sauf que vous ne commandez maintenant que les 5 premiers éléments après les avoir sélectionnés. Il peut être plus rapide, mais il a également une sémantique différente, qui est moins susceptible d'être ce que les gens veulent réellement atteindre.
Greg Beech
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.