This article is currently in the process of being translated into Russian (~98% done).
Limiting data: the Take() & Skip() methods
До сих пор в этой главе руководства по LINQ мы обнаружили несколько способов работы с источниками данных с использованием LINQ. Теперь пришло время посмотреть, как мы можем ограничить объем данных для работы. Это особенно полезно при использовании базы данных в качестве источника данных, поскольку она часто включает в себя огромное количество строк, извлечение которых требует больших ресурсов.
Методы, которые мы обсудим в этой статье, называются Take() и Skip(), и в сочетании они отлично подходят для выполнения таких вещей, как разбивка на страницы на веб-сайте. На самом деле, они часто используются вместе, но, конечно, их можно использовать и по отдельности. Метод Take() даст вам X количество элементов из источника данных, в то время как Skip() позволит вам игнорировать первые X элементов. Простой пример будет выглядеть следующим образом:
List<string> names = new List<string>()
{
"John Doe",
"Jane Doe",
"Joe Doe",
"Jenna Doe",
};
var middleNames = names.Skip(1).Take(2).ToList();
foreach (var name in middleNames)
Console.WriteLine(name);
Мы создаем простой список имен, а затем для вывода пропускаем первое имя (Skip(1)), а затем берем следующие два имени (Take (2)), в основном оставляя нам только два средних имени из списка.
Базовая разбивка на страницы с помощью Skip() и Take()
Как вы можете видеть, оба метода Take() и Skip () очень просты в использовании, но их интереснее продемонстрировать с большим количеством данных, чем мы использовали ранее, поэтому я взял на себя смелость создать немного более сложный пример, который лучше продемонстрирует, как эти методы могут помочь вам. Во-первых, вот код для этого:
using System;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
namespace LinqTakeSkip1
{
class Program
{
static void Main(string[] args)
{
CultureInfo usCulture = new CultureInfo("en-US");
XDocument xDoc = XDocument.Load("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
var cubeNodes = xDoc.Descendants().Where(n => n.Name.LocalName == "Cube" && n.Attribute("currency") != null).ToList();
var currencyRateItems = cubeNodes.Select(node => new
{
Currency = node.Attribute("currency").Value,
Rate = double.Parse(node.Attribute("rate").Value, usCulture)
});
int pageSize = 5, pageCounter = 0;
var pageItems = currencyRateItems.Take(pageSize);
while(pageItems.Count() > 0)
{
foreach (var item in pageItems)
Console.WriteLine(item.Currency + ": " + item.Rate.ToString("N2", usCulture));
Console.WriteLine("Press any key to get the next items...");
Console.ReadKey();
pageCounter++;
// Here's where we use the Skip() and Take() methods!
pageItems = currencyRateItems.Skip(pageSize * pageCounter).Take(pageSize);
}
Console.WriteLine("Done!");
}
}
}
Это довольно большой фрагмент кода, но давайте пробежимся по нему. В первой половине мы проанализируем общедоступный XML-источник курсов обмена валют. Это дает мне возможность кратко показать вам LINQ to XML, который является очень интересной частью экосистемы LINQ. Мы обсудим LINQ to XML в другой статье, но пока просто знайте, что мы используем его для извлечения важных узлов из источника XML и помещения их в анонимные объекты, состоящие из названия и текущего обменного курса валюты, которые мы будем использовать позже.
Теперь у нас есть хороший источник данных о валюте в переменной currency Rate Items. В последней половине примера мы используем этот источник для выполнения некоторой простой разбивки на страницы - мы просто извлекаем 5 записей, а затем просим пользователя нажать клавишу, чтобы получить следующие 5 (или сколько бы их ни осталось в источнике). Мы делаем это, извлекая первые 5 записей, а затем используем цикл while для непрерывного извлечения следующих 5 записей, пока источник не опустеет. Получение следующих 5 записей осуществляется с помощью комбинации Skip() и Take() - вся основа этой статьи.
Summary
Методы Skip() и Take() очень просты в использовании, но, тем не менее, очень полезны во многих ситуациях. Как уже упоминалось, они часто используются вместе, но особенно метод Take() с таким же успехом может использоваться отдельно.