Programming Taskbook 0


Обработка пустой последовательности


Download 1.62 Mb.
Pdf ko'rish
bet50/71
Sana21.06.2023
Hajmi1.62 Mb.
#1644761
TuriУчебное пособие
1   ...   46   47   48   49   50   51   52   53   ...   71
Bog'liq
Abramyan-Pascal2016-1

Обработка пустой последовательности
Метод sequence of T
 
DefaultIfEmpty(defaultValue: T): sequence of T 
Запрос DefaultIfEmpty может применяться к последовательности с эле-
ментами любого типа T и имеет один необязательный параметр defaultValue 
того же типа T. Если исходная последовательность является непустой, то 
он возвращает эту последовательность в неизменном виде; в противном 
случае он возвращает последовательность, содержащую единственный 
элемент со значением defaultValue (или с нулевым значением соответству-
ющего типа, если параметр defaultValue не указан). Таким образом, в ре-
зультате применения запроса DefaultIfEmpty мы всегда будем получать непу-
стую последовательность. 
Чтобы предыдущий фрагмент правильно конструировал плоское левое 
внешнее объединение, достаточно добавить в него запрос DefaultIfEmpty: 
var res := a1.GroupJoin(a2, e1 -> e1 mod 10, e2 -> e2 mod 10,
(e1, e2) -> e2.DefaultIfEmpty.Select(e -> (e1, e))) 
.SelectMany(e -> e);
Write(res); // [(10,40),(10,60),(21,51),(33,53),(84,0)] 
Теперь в полученной последовательности будет присутствовать пара с 
элементом 84, который будет связан с особым значением 0. 
Завершая обзор запросов Join и GroupJoin, заметим, что для них исполь-
зуется эффективная реализация, не сводящаяся к двойному циклу с попар-
ными проверками ключей: внутренняя последовательность предваритель-
но преобразуется к специальной структуре данных — таблице просмотра


Глава 4. Запросы 
81 
индексированной по ключу, что позволяет находить ее элементы, парные к 
элементам внешней последовательности, не прибегая к их многократному 
перебору (по поводу таблицы просмотра см. также п. 4.6). 
Иногда требуется построить последовательность, состоящую из все-
возможных пар, в которых первый элемент берется из первой последова-
тельности, а второй элемент — из второй. Такой набор пар называется де-
картовым произведением исходных последовательностей. Его можно 
сформировать с помощью запроса Join, если задать один и тот же ключ для 
всех элементов обеих последовательностей (например, число 0). Однако 
такой способ формирования декартова произведения будет неэффектив-
ным, поскольку потребует выполнения множества дополнительных дей-
ствий (в частности, создания таблицы просмотра). Для эффективного фор-
мирования декартова произведения можно использовать комбинацию за-
просов SelectMany и Select: 
var a1 := Seq(1, 2, 3); 
var a2 := Seq(10, 20); 
var res := a1.SelectMany(e1 -> a2.Select(e2 -> (e1, e2)));
Write(res); // [(1,10),(1,20),(2,10),(2,20),(3,10),(3,20)] 
Чтобы не конструировать каждый раз подобную комбинацию запро-
сов, в библиотеку PascalABC.NET включен запрос Cartesian, специально 
предназначенный для формирования декартова произведения, и содержа-
щий единственный параметр — имя второй последовательности:
var res2 := a1.Cartesian(a2);
Последовательность res2, полученная в результате выполнения этого 
запроса, будет совпадать с последовательностью res из предыдущего фраг-
мента. Запрос Cartesian может содержать дополнительный параметр — 
лямбда-выражение, определяющее преобразование, которое будет приме-
нено к каждой паре элементов декартова произведения перед помещением 
результата в итоговую последовательность. 
Оставшиеся запросы объединения имеют в своем названии слово Zip; 
все эти запросы объединяют (тем или иным способом) элементы исходных 
последовательностей с одинаковыми индексами. Если таким образом объ-
единяются последовательности разного размера, то полученная последова-
тельность будет иметь размер, равный наименьшему размеру исходных по-
следовательностей («лишние» элементы более длинных последовательно-
стей не обрабатываются). 
В запросе Zip из стандартной библиотеки платформы .NET способ 
объединения элементов задается в виде лямбда-выражения, например: 
var a1 := Seq(3, 4, 5, 6); 
var a2 := Seq(50, 60, 70); 
var res := a1.Zip(a2, (e1, e2) -> e1 * e2);


82 
Write(res); // [150,240,350] 
С помощью этого же запроса можно получить последовательность пар 
(кортежей) соответствующих элементов:
var res2 := a1.Zip(a2, (e1, e2) -> (e1, e2));
Write(res2); // [(3,50),(4,60),(5,70)] 
В PascalABC.NET последнюю задачу можно решить проще, использо-
вав специальный запрос ZipTuple с единственным параметром — второй 
последовательностью: a1.ZipTuple(a2). 
Запрос ZipTuple имеет перегруженные варианты, позволяющие объеди-
нять соответствующие элементы трех и четырех последовательностей: 
var a1 := Seq(3, 4, 5, 6); 
var a2 := Seq(50, 60, 70); 
var a3 := Seq('a', 'b', 'c'); 
var a4 := Seq(1.1, 2.2, 3.3); 
var res := a1.ZipTuple(a2, a3, a4); 
Write(res); // [(3,50,a,1.1),(4,60,b,2.2),(5,70,c,3.3)] 
Имеется запрос UnzipTuple без параметров, выполняющий обратное 
действие, т. е. расщепляющий исходную последовательность кортежей 
(пар, троек или четверок) на соответствующее количество результирую-
щих последовательностей (которые возвращаются в виде кортежа после-
довательностей). Например, имея последовательность res из предыдущего 
примера, можно «восстановить» последовательности a1, a2, a3, a4 следую-
щим образом (используя кортежное присваивание): 
(a1, a2, a3, a4) := res.UnzipTuple; 
Запрос UnzipTuple можно отнести к категории специализированных за-
просов расщепления, рассмотренных в п. 4.2. 
Обратимся к задачам из группы LinqBegin. 
В задаче LinqBegin51 даются последовательности a и b положитель-
ных целых чисел, причем все числа в последовательности a различны. 
Требуется получить последовательность строк вида «s:e», где s обозначает 
сумму тех чисел из b, которые оканчиваются на ту же цифру, что и число e 
— один из элементов последовательности a (например, «74:23»); если для 
числа e не найдено ни одного подходящего числа из последовательности b, 
то в качестве s надо указать 0. Элементы полученной последовательности 
должны располагаться по возрастанию значений найденных сумм, а при 
равных суммах — по убыванию значений элементов a. 
Поскольку в полученную последовательность надо включать также и 
элементы исходной последовательности a, для которых в последователь-
ности b отсутствуют соответствующие элементы (оканчивающиеся на ту 
же цифру), нам необходимо построить левое внешнее объединение, исполь-


Download 1.62 Mb.

Do'stlaringiz bilan baham:
1   ...   46   47   48   49   50   51   52   53   ...   71




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling