Подкачка коллекции с помощью LINQ
Как вы просматриваете коллекцию в LINQ, учитывая, что у вас есть startIndex
и count
?
4 ответа:
несколько месяцев назад я написал сообщение в блоге о Fluent Interfaces и LINQ, которые использовали метод расширения на
IQueryable<T>
и другой класс, чтобы обеспечить следующий естественный способ разбиения на страницы коллекции LINQ.var query = from i in ideas select i; var pagedCollection = query.InPagesOf(10); var pageOfIdeas = pagedCollection.Page(2);
вы можете получить код со страницы галереи кодов MSDN:конвейеры, фильтры, Fluent API и LINQ to SQL.
Это очень просто с помощью тега
Skip
иTake
методы расширения.var query = from i in ideas select i; var paggedCollection = query.Skip(startIndex).Take(count);
я решил это немного по-другому, чем у других, поскольку мне пришлось сделать свой собственный пагинатор с повторителем. Поэтому я сначала сделал коллекцию номеров страниц для коллекции элементов, которые у меня есть:
// 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]
используя это, я мог бы легко разбить коллекцию элементов на коллекцию "страниц". Страница в данном случае-это просто набор элементов (
IEnumerable<Item>
). Это, как вы можете сделать это с помощьюSkip
иTake
вместе с выбором индекса изpageRange
создал выше:IEnumerable<IEnumerable<Item>> pageRange .Select((page, index) => myItems .Skip(index*PageSize) .Take(PageSize));
конечно, вы должны обрабатывать каждую страницу в качестве дополнительной коллекции, но, например, если вы вложенные повторители, то это на самом деле легко обрабатывать.
The однострочный TLDR версия будет такая:
var pages = Enumerable .Range(0, pageCount) .Select((index) => myItems.Skip(index*PageSize).Take(PageSize));
который можно использовать как это:
for (Enumerable<Item> page : pages) { // handle page for (Item item : page) { // handle item in page } }
этот вопрос несколько устарел, но я хотел опубликовать свой алгоритм подкачки, который показывает всю процедуру (включая взаимодействие с пользователем).
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);
однако, если вы после производительности и в производственном коде, мы все после производительности, вы не должны использовать подкачку LINQ, как показано выше, а скорее базовую
IEnumerator
для реализации подкачки самостоятельно. На самом деле, это так же просто, как LINQ-алгоритм, показанный выше, но больше исполнитель: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); }
объяснение: недостаток использования
Skip()
для нескольких раз " каскадным образом "является то, что он не будет действительно хранить" указатель " итерации, где он был пропущен в последний раз. - Вместо этого исходная последовательность будет загружена с пропуском вызовов, что приведет к" потреблению "уже" потребленных " страниц снова и снова. - Вы можете доказать это сами, когда создадите последовательностьideas
так что он дает побочные эффекты. -> Даже если вы пропустили 10-20 и 20-30 и хотите обработать 40+, вы увидите, что все побочные эффекты 10-30 выполняются снова, прежде чем вы начнете повторять 40+. Вариант с использованиемIEnumerable
интерфейс напрямую, вместо этого будет помнить положение конца последней логической страницы, поэтому явный пропуск не требуется, и побочные эффекты не будут повторяться.