Шрифт:
Этот оператор возвращает данные, сгруппированные в последовательности, при чем каждую последовательность обозначает общий ключ.
Результатом выполнения оператора group является последовательность, состоя щая из элементов типа IGrouping<TKey, TElement>, т.е. обобщенного интерфейса, объявляемого в пространстве имен System.Linq. В этом интерфейсе определена кол лекция объектов с общим ключом. Типом переменной запроса, возвращающего груп пу, является IEnumerable<IGrouping<TKey, TElement>>. В интерфейсе IGrouping определено также доступное только для чтения свойство Key, возвращающее ключ, связанный с каждой коллекцией.
Ниже приведен пример, демонстрирующий применение оператора group. В коде этого примера сначала объявляется массив, содержащий список веб-сайтов, а затем формируется запрос, в котором этот список группируется по имени домена самого верхнего уровня, например .org или .com. // Продемонстрировать применение оператора group. using System; using System.Linq; class GroupDemo { static void Main { string[] websites = { "hsNameA.com", "hsNameB.net", "hsNameC.net", "hsNameD.com", "hsNameE.org", "hsNameF.org", "hsNameG.tv", "hsNameH.net", "hsNameI.tv" }; // Сформировать запрос на получение списка веб-сайтов, // группируемых по имени домена самого верхнего уровня. var webAddrs = from addr in websites where addr.LastIndexOf('.') != -1 group addr by addr.Substring(addr.LastIndexOf('.')); // Выполнить запрос и вывести его результаты. foreach(var sites in webAddrs) { Console.WriteLine("Веб-сайты, сгруппированные " + "по имени домена" + sites.Key); foreach(var site in sites) Console.WriteLine(" " + site); Console.WriteLine; } } }
Вот к какому результату приводит выполнение этого кода. Веб-сайты, сгруппированные по имени домена .соm hsNameA.com hsNameD.com Веб-сайты, сгруппированные по имени домена .net hsNameB.net hsNameC.net hsNameH.net Веб-сайты, сгруппированные по имени домена .org hsNameE.org hsNameF.org Веб-сайты, сгруппированные по имени домена .tv hsNameG.tv hsNameI.tv
Как следует из приведенного выше результата, данные, получаемые по запросу, группируются по имени домена самого верхнего уровня в адресе веб-сайта. Обратите внимание на то, как это делается в операторе group из следующего запроса. var webAddrs = from addr in websites where addr.LastlndexOf('.') != -1 group addr by addr.Substring(addr.LastIndexOf('.'));
Ключ в этом операторе создается с помощью методов LastIndexOf и Substring, определенных для данных типа string. (Эти методы упоминаются в главе 7, посвященной массивам и строкам. Вариант метода Substring, исполь зуемый в данном примере, возвращает подстроку, начинающуюся с места, обозна чаемого индексом, и продолжающуюся до конца вызывающей строки.) Индекс по следней точки в адресе веб-сайта определяется с помощью метода LastIndexOf. По этому индексу в методе Substring создается оставшаяся часть строки, в ко торой содержится имя домена самого верхнего уровня. Обратите внимание на то, что в операторе where отсеиваются все строки, которые не содержат точку. Метод LastIndexOf возвращает -1, если указанная подстрока не содержится в вызываю щей строке.
Последовательность результатов, получаемых при выполнении запроса, храняще гося в переменной webAddrs, представляет собой список групп, поэтому для доступа к каждому члену группы требуются два цикла foreach. Доступ к каждой группе осу ществляется во внешнем цикле, а члены внутри группы перечисляются во внутреннем цикле. Переменная шага внешнего цикла foreach должна быть экземпляром интер фейса IGrouping, совместимым с ключом и типом элемента данных. В рассматри ваемом здесь примере ключи и элементы данных относятся к типу string. Поэтому переменная sites шага внешнего цикла имеет тип IGrouping, а переменная site шага внутреннего цикла — тип string. Ради краткости данного примера обе переменные объявляются неявно, хотя их можно объявить и явным об разом, как показано ниже. foreach(IGrouping<string, string> sites in webAddrs) { Console.WriteLine("Веб-сайты, сгруппированные " + "по имени домена" + sites.Key); foreach(string site in sites) Console.WriteLine(" " + site); Console.WriteLine; } Продолжение запроса с помощью оператора into
При использовании в запросе оператора select или group иногда требуется сфор мировать временный результат, который будет служить продолжением запроса для по лучения окончательного результата. Такое продолжение осуществляется с помощью оператора into в комбинации с оператором select или group. Ниже приведена об щая форма оператора into: into имя тело_запроса
где имя обозначает конкретное имя переменной диапазона, используемой для ци клического обращения к временному результату в продолжении запроса, на которое указывает тело_запроса. Когда оператор into используется вместе с оператором select или group, то его называют продолжением запроса, поскольку он продолжает запрос. По существу, продолжение запроса воплощает в себе принцип построения нового запроса по результатам предыдущего.
ПРИМЕЧАНИЕ Существует также форма оператора into, предназначенная для использования вместе с оператором join, создающим групповое объединение, о котором речь пойдет далее в этой главе.
Ниже приведен пример программы, в которой оператор into используется вместе с оператором group. Эта программа является переработанным вариантом предыду щего примера, в котором список веб-сайтов формируется по имени домена самого верхнего уровня. А в данном примере первоначальные результаты запроса сохраня ются в переменной диапазона ws и затем отбираются для исключения всех групп, со стоящих менее чем из трех элементов. // Использовать оператор into вместе с оператором group. using System; using System.Linq; class IntoDemo { static void Main { string[] websites = { "hsNameA.com", "hsNameB.net", "hsNameC.net", "hsNameD.com", "hsNameE.org", "hsNameF.org", "hsNameG.tv", "hsNameH.net", "hsNameI.tv" }; // Сформировать запрос на получение списка веб-сайтов, группируемых // по имени домена самого верхнего уровня, но выбрать только те // группы, которые состоят более чем из двух членов. // Здесь ws — это переменная диапазона для ряда групп, // возвращаемых при выполнении первой половины запроса. var webAddrs = from addr in websites where addr.LastIndexOf('.') != -1 group addr by addr.Substring(addr.LastIndexOf('.')) into ws where ws.Count > 2 select ws; // Выполнить запрос и вывести его результаты. Console.WriteLine("Домены самого верхнего уровня " + "с более чем двумя членами.\n"); foreach(var sites in webAddrs) { Console.WriteLine("Содержимое домена: " + sites.Key); foreach(var site in sites) Console.WriteLine(" " + site); Console.WriteLine; } } }
Эта программа дает следующий результат: Домены самого верхнего уровня с более чем двумя членами. Содержимое домена: .net hsNameB.net hsNameC.net hsNameH.net
Как следует из результата выполнения приведенной выше программы, по запросу возвращается только группа .net, поскольку это единственная группа, содержащая больше двух элементов.
Обратите особое внимание в данном примере программы на следующую последо вательность операторов в формируемом запросе. group addr by addr.Substring(addr.LastIndexOf('.')) into ws where ws.Count >2 select ws;