Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 144
Текст из файла (страница 144)
51пс( и унаследован от 1ЕписзегзЬ1е. Поэтому 10гоир1пи можно применять везде, где можно использовать интерфейс Тепипсегаь1е. интерфейс 10гоирьп0 включает свойство по имени кеу, которое является объектом, описывающим подмножество. Каждый результирующий набор формируется применением операции эквивалентности к входным данным и Кеу. Давайте рассмотрим пример, принимающий последовательность целых числен и разбивающий их на множества четных и нечетных чиселп.
из1пч Яузгеяп иззп9 яуяпев.ь1пс)7 риЬ11с с1аяя Ягоиркхаспр1е ( япагьс чосб Маап() ( 1пс[) сивЬегя = ( О, 1, 2, 3, 4, 5, Я, 7, 8, 9 я При обсуждении конструкции чгоир используется понятие разбиение из теории множеств. Разбиение множества пространства Я вЂ” это множество непересекающихся подмножеств, объединение которых дает Я. 1))(О: язык интегрированных запросов 539 Разделение чисел нз четные и нечетные.
чаг доегу = Егов к пп ичвьегз дгоир к Ьу к % 2т полезен( чаг дгоор 1л диасу ) ( Соляо1е.ыгьпеЬзле( "вес)2 == (О)", дгоар.хеу ) тогезсЬ( чаг псвЬег по дгоир ) ( Сопяо1е.ыг1ге( "(О), ", лшпЬег ) Сопяо1е.игзсещпе( "Чп" ) ) ) Прежде всего, обратите внимание, что в запросе отсутствует конструкщкя зе1есс. Конечным результатом запроса является последовательность из двух экземпляров 1дгонр1лд, те. 1ЕповегзЬ1е<16гоир1пд<1пс». Первый экземпляр — результирующая последовательность, содержащая четные числа, а вторая содержит нечетные числа, нак показано в следующем выводе: вос(2 == О О, 2, 4, б, 8, вос)2 == 1 1, 3, 5, 7, 9, Первый оператор богеасн выполняет итерацию по двум группам или, точнее, по двум экземплярам 16гоорупд.
И поскольку каждый 16гонрз пд реализует 1ЕповегзЫе, здесь присутствует вложенный цикл богезсЬ, осуществляющий итерацию по всем элементам группы. Как видите, этот простой запрос проходит по всем элементам исходной коллекции данных гпнпЬег я и производит две результирующих группы. Внутренне компилятор транслирует каждую конструкцию дгоир в вызов стандартной операции запроса СгоорВу. Конструкция дгоор может также разбивать входную коллекцию, используя множественные ключи, также называемые сосгпавиыми ключами. Их можно воспринимать как разбиение по одному ключу, состоящему из нескольких порций данных.
Чтобы вьпюлнить такую группировку, можно воспользоваться анонимным типом для представления множественных ключей в запросе, как показано в следующем примере: изгпд Яуясевт иятод Яузпев.ьпос11 пекод Яузсев.Со11ессгооя.белег1ст рсЬ1пс с1азя Евр1оуее ( рпЫпс ягггпд Ьаяскаве ( дест пест ) РоЫ1с зсгзпд Р1гягызве ( дест зепг рсЫЬс ясгтпд Магпопя11су ( дес; вест ) роЬ1гс с1азя Огоиркхзвр1е ( ясастс чо1с( Иазп() ( чзг ептр1оуеея = лен Ьвяс<Евр1оуее> () ( пен Евр1оуее ( Ьаясыаве = ацопез", Гтгяснаве = "Ес(", Маппопа11су = "Лвег1сзп" пен Евр1оуее ( Ьаяскаве = "1чапоч", Ртгягкаве = "Чаяуа", 540 Глава 16 Магвопа11гу = папвя1ап" пе» Епр1оуее ( Ьаягкапе = пдопев", Е1гяСМапе = "Топ", МаСЬопя11гу = "Ие1яь" пе» Епр1оуее ( Ьавгкапе = "Япа11в", ЕсгвСМапе = "Ярзп1оапд", МаС1опа11Су = "Тгаяь" ), пе» Епр1оуее ( Ьавгнапе = "Тчапоч", Евгвгкапе = "1чап", Магаопа11Су = "Кияваап" ) чаг с(песу» Егоп епр Еп ешр1оуеея дгопр еар )ву пе» ( Наеаопа11еу = епр.ЫаС1опа11еу, Ьаяеиапе = епр.ьавеиапе )' Гогеасп( чяг дгопр Тп Чпегу ) Сопво1е.нгтгеЬ1пе( дгопр.кеу ); Тогеась( чзг епр1оуее Ьп дгопр ) ( Сопво1е.кг Сеьспе( епр1оуее.гагяСМапе ) ) Сопво1е.игсгеЬ1пе(); Обратите внимание на анонимный тип внутри конструкции дгопр.
Он говорит о том, что входная коллекция должна быть разбита на группы, в которых одинаковы масаопа11су н ьаясмапе. В данном примере каждая группа в конечном итоге получает по одной сущности, за исключением одной — той, где мас1па11су имеет значение Епввсап. а Ьавгнапе — 1чапоч. По сути, это работает следующим образом: строится экземпляр анонимноготипа,н экземпляр ключа проверяется на эквивалентность ключу существующей группы. Если эквивалентность имеет место, элемент попадает в эту группу. а если нет, то создается новая группа с экземпляром анонимного типа в качестве ключа. Запуск предыдущего кода на выполнение дает следующий результат: ( Мягсопа11Су Ес( ( МаСТопа11Су чавуз Тчяп ( Мягаопа11гу Топ ( Мягаопя11гу Яряп1с)1пд = Апегссап, Ьаягкапе = Юопев ) = Епяягап, Ьаягкапе = Тчапоч ) = Ие1я)с, Ьавгнапе = Яопев ) = 1гавь, Ьзвгнапе = Япа11я ) Группировка полезна сама по себе.
Однако что, если необходимо дополнительно оперировать каждой группой внутри запроса, таким образом. трактуя результирующее разбиение на группы в качестве промежуточного шага? В данной ситуации используется ключевое слово Ьпсо, описанное в следующем разделе. В)(0: язык интегрированных запросов 541 Конструкция ~п~о и продолжение Ключевое слово 1пко подобно ключевому слову 1ег в том, что оно определяет локальный по отношению к контексту запроса идентификатор. Используя конструкцию 1пго, вы сообщаете запросу, что хотите присвоить результат операции Ого пр или 9 оап идентификатору, который может быть использован в запросе позднее. На языке запросов это называется продоллсеиием (сопйппайоп), поскольку конструкция дгопр не является финальным проектором запроса.
Однако конструкция 1пгс работает как генератор, во многом подобно конструкциям 1гов, и идентификатор, представленный анко, подобен переменной диапазона в конструкции 1гов. Рассмотрим пример: пя1пд Яуягевт пв1пд Яуясев.11пс(т рпЬ11с с1авв ОгопрЕхавр1е ( ягагас чоаб Ма1п() ( апг() ппвЬегя = ( О, 1, 2, 3, 4, 5, б, 7, Е, 9 )т // Разбиение чисел на четные и нечетные. чаг дпегу = Угон к гп питЬегя дгопр к Ьу х $2 1пео рагс1С1оп ипате рагеас1оп.Кеу = 0 яе1еое пеи ( Кеу = раге1С1оп.деу, попас = регс1С1оп.сочпе(), Пипар рагеас1оп )т когеасл( чаг згев 1п Чпегу ) ( Сопяс1е.иг1се11пе( "воб2 == (О)", гоев.Кеу ); Сспво1е.иг1се11пе( "Сопок == (0)", акев.Ссппг ); тогевсп( чаг ппвЬег 1п 1гев.огспр ) ( Сопвс1е.игаге( "(0), ", ппвпег ); Сспяо1е.игаге11пе( "М" ): В этом запросе продолжение, те.
часть запроса, следующая после конструкции 1п го, фИльтрует последовательности групп, где Кеу равно О, с использованием конструкции ипеге. Так фильтруется группа четных чисел. Затем эта группа проектируется на анонимный тип, поддерживая счетчик элементов в группе, который сопровождается значением свойства Кеу и элементами группы. В результате вывод на консоль включает только одну группу А что, если понадобится добавить счетчик в каждую группу раздела7 Как уже упоминалось, конструкция 1пко — это генератор. Поэтому желаемый результат можно получить, изменив запрос следующим образом: чаг Ччегу = 1гсв х ап ппвЬегя дгспр х Ьу х $2 апго рагкагтоп ве1есс пеи ( Кеу = рагсас1оп.Кеу, Ссппг = рагс1К1оп.ссипк(), Огсчр = Раггасаоп 542 Глава 16 Как ведите, конструкция нпе ге была удалена.
таким образом удаляя всю фильтрацию. При выполнении этой версии запроса получается такой вывод: пюп2 == О Соипг == 5 О, 2, ч, б, 8, пюг12 == 1 Соопс == 5 1, 3, 5, 7, 9, Обратите внимание, что в обоих предыдущих выражениях запросов результатом является не 1ЕпплгегаЬ1е<16гопр1од<Т», как это обычно бывает, когда конструкция Огопр является финальной проекцией. Вместо этого конечным результатом будет 1Е ппяегаЬ1е<Т>. где Т заменяется анонимным типом. Преимущества лени В операторе, где строится выражение запроса ЫХЯ и присваивается переменной запроса, выполняется очень мало кода. Данные становятся доступными только во время итерации по этой переменной запроса, которая выполняет запрос по одному разу для каждого элемента в результирующем наборе.
Поэтому, например, если результирующий набор состоит из 100 элементов, а итерация выполняется только по первым 10, то не приходится платить за вычисление остальных 90 элементов результирующего набора, если только не применяется операция вроде яке гете, которая требует итерации по всей коллекции. Нв заметку! Для обращения к указанному количеству элементов в начале заданного потока можно использовать расширяющий метод Тахе, который производит отложенный исполняемый пере- числитель.
Не менее полезны в этом плане также методы Тахекп11е, 5КТР и 5К1РХЬз1е. Выгоды подхода на основе отложенного выполнения многочисленны. Прежде всего, операции, описанные в выражении запроса, могут оказаться достаточно дорогими. Поскольку эти операции предоставляются пользователем, и проектировщики ЫХЯ не имеют никакой возможности прогнозировать сложность этих операций, лучше получать каждый элемент лишь по мере необходимости.
К тому же данные могут находиться в базе данных, физически расположенной в другом полушарии. В этом случае определенно следует отдать предпочтение "ленивому" вычислению на своей стороне. И, наконец, переменная диапазона может в принципе выполнять итерацию по бесконечной последовательности. В следующем разделе будет приведен пример. Поощрение лени итераторами СФ Внутренне переменная запроса реализуется посредством итераторов СЕ с использованием ключевого слова узе1с1, В главе 9 объяснялось, что код, содержащий операторы у1е1Ш в действительности компилируется в объект итератора. Поэтому, когда выражение Ы1Щ присваивается переменной запроса, единственный код, выполняющийся при этом — это код конструктора объекта итератора.










