Programming Taskbook 0
Обработка пустой последовательности
Download 1.62 Mb. Pdf ko'rish
|
Abramyan-Pascal2016-1
- Bu sahifa navigatsiya:
- .DefaultIfEmpty
- [(1,10),(1,20),(2,10),(2,20),(3,10),(3,20)]
- [150,240,350]
- [(3,50),(4,60),(5,70)]
- [(3,50,a,1.1),(4,60,b,2.2),(5,70,c,3.3)]
Обработка пустой последовательности
Метод 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 отсутствуют соответствующие элементы (оканчивающиеся на ту же цифру), нам необходимо построить левое внешнее объединение, исполь- |
Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling
ma'muriyatiga murojaat qiling