Paging une collection avec LINQ

voix
69

Comment à travers une collection de LINQ faire page vous étant donné que vous avez startIndexet count?

Créé 01/08/2008 à 14:20
source utilisateur
Dans d'autres langues...                            


4 réponses

voix
61

Il est très simple avec les Skipet Takeméthodes d' extension.

var query = from i in ideas
            select i;

var paggedCollection = query.Skip(startIndex).Take(count);
Créé 01/08/2008 à 14:22
source utilisateur

voix
38

Quelques mois , j'ai écrit un blog sur Interfaces Courant et LINQ qui a utilisé une méthode d' extension sur IQueryable<T>et une autre classe pour fournir la manière naturelle à la suite de paginer une collection LINQ.

var query = from i in ideas
            select i;
var pagedCollection = query.InPagesOf(10);
var pageOfIdeas = pagedCollection.Page(2);

Vous pouvez obtenir le code du MSDN Code Gallery Page: Pipelines, Filtres, API Fluent et LINQ to SQL .

Créé 07/08/2008 à 09:22
source utilisateur

voix
12

Je résolu ce problème un peu différemment de ce que les autres ont que je devais faire mon propre paginator, avec un répéteur. Donc, j'ai fait une collection de numéros de page pour la collection d'articles que j'ai:

// assumes that the item collection is "myItems"

int pageCount = (myItems.Count + PageSize - 1) / PageSize;

IEnumerable<int> pageRange = Enumerable.Range(1, pageCount);
   // pageRange contains [1, 2, ... , pageCount]

L' utilisation de ce que je pourrais facilement diviser la collection d'éléments dans une collection de « pages ». Une page dans ce cas est simplement une collection d'objets ( IEnumerable<Item>). Voici comment vous pouvez le faire en utilisant Skipet en Takemême temps que la sélection de l'indice de la pageRangecréé ci - dessus:

IEnumerable<IEnumerable<Item>> pageRange
    .Select((page, index) => 
        myItems
            .Skip(index*PageSize)
            .Take(PageSize));

Bien sûr, vous devez gérer chaque page comme une collection supplémentaire, mais par exemple si vous êtes répéteurs nichant alors c'est en fait facile à manipuler.


Le TLDR one-liner version serait la suivante:

var pages = Enumerable
    .Range(0, pageCount)
    .Select((index) => myItems.Skip(index*PageSize).Take(PageSize));

Ce qui peut être utilisé comme ceci:

for (Enumerable<Item> page : pages) 
{
    // handle page

    for (Item item : page) 
    {
        // handle item in page
    }
}
Créé 20/03/2012 à 13:52
source utilisateur

voix
9

Cette question est un peu vieux, mais je voulais poster mon algorithme de recherche de personnes qui montre toute la procédure (y compris l'interaction de l'utilisateur).

const int pageSize = 10;
const int count = 100;
const int startIndex = 20;

int took = 0;
bool getNextPage;
var page = ideas.Skip(startIndex);

do
{
    Console.WriteLine("Page {0}:", (took / pageSize) + 1);
    foreach (var idea in page.Take(pageSize))
    {
        Console.WriteLine(idea);
    }

    took += pageSize;
    if (took < count)
    {
        Console.WriteLine("Next page (y/n)?");
        char answer = Console.ReadLine().FirstOrDefault();
        getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);

        if (getNextPage)
        {
            page = page.Skip(pageSize);
        }
    }
}
while (getNextPage && took < count);

Toutefois, si vous êtes après la performance, et le code de production, nous sommes tous après la performance, vous ne devriez pas utiliser la pagination de LINQ comme indiqué ci - dessus, mais plutôt le sous - jacent IEnumeratorà mettre en œuvre vous - même pagination. En fait, il est aussi simple que l'algorithme LINQ illustré ci - dessus, mais plus performant:

const int pageSize = 10;
const int count = 100;
const int startIndex = 20;

int took = 0;
bool getNextPage = true;
using (var page = ideas.Skip(startIndex).GetEnumerator())
{
    do 
    {
        Console.WriteLine("Page {0}:", (took / pageSize) + 1);

        int currentPageItemNo = 0;
        while (currentPageItemNo++ < pageSize && page.MoveNext())
        {
            var idea = page.Current;
            Console.WriteLine(idea);
        }

        took += pageSize;
        if (took < count)
        {
            Console.WriteLine("Next page (y/n)?");
            char answer = Console.ReadLine().FirstOrDefault();
            getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);
        }
    }
    while (getNextPage && took < count);
}

Explication: L'inconvénient de l' utilisation Skip()de plusieurs fois d'une manière « en cascade » est, que ce ne sera pas vraiment stocker le « pointeur » de l'itération, où elle avait été ignorée. - Au lieu de cela la séquence originale sera chargée par l' avant avec les appels de saut, qui conduisent à des pages « consommer » les déjà « consommé » encore et encore. - Vous pouvez prouver que vous, lorsque vous créez la séquence ideasafin qu'il donne des effets secondaires. -> Même si vous avez sauté 10-20 et 20-30 et que vous voulez traiter de plus de 40, vous verrez tous les effets secondaires de 10-30 en cours d' exécution à nouveau, avant de commencer à itérer de plus de 40. La variante en utilisant IEnumerablel'interface « directement, au lieu se rappeler la position de la fin de la dernière page logique, donc pas explicite est nécessaire skipping et les effets secondaires ne sera pas répétée.

Créé 16/07/2011 à 21:07
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more