Programming Taskbook 0


Download 1.62 Mb.
Pdf ko'rish
bet46/71
Sana21.06.2023
Hajmi1.62 Mb.
#1644761
TuriУчебное пособие
1   ...   42   43   44   45   46   47   48   49   ...   71
Bog'liq
Abramyan-Pascal2016-1


Глава 4. Запросы 
75 
Если же заменить в приведенном фрагменте запрос Select на запрос Se-
lectMany, то элементы полученных в лямбда-выражении последовательно-
стей запишутся в итоговую последовательность в «плоском» виде:
var a := Range(12,15).SelectMany(e -> Seq(e div 10, e mod 10)); 
Write(a); // [1,2,1,3,1,4,1,5] 
Имеет смысл проиллюстрировать и применение второго, более слож-
ного варианта запроса SelectMany, использующего два селектора. Изменим 
предыдущий пример так, чтобы в формируемой последовательности со-
хранять не отдельную цифру каждого исходного числа, а само исходное 
число, к которому справа приписана одна из его цифр (например, по числу 
12 мы хотим получить два числа: 121 и 122). С применением второго вари-
анта запроса SelectMany это можно реализовать следующим образом: 
var a := Range(12,15).SelectMany(e -> Seq(e div 10, e mod 10),
(e, d) -> e * 10 + d); 
Write(a); // [121,122,131,133,141,144,151,155] 
Чтобы подчеркнуть, что в обоих селекторах в качестве первого пара-
метра используется элемент исходной последовательности, мы выбрали 
для этих параметров одно и то же имя: e. Второй параметр второго селек-
тора является одной из тех цифр, которая была получена при «расщепле-
нии» числа e; для этого параметра мы выбрали имя d (от англ. digit — 
«цифра»). 
Имеются модификации запросов Select и SelectMany, в которых в каче-
стве дополнительного параметра селектора sel можно использовать индекс 
обрабатываемого элемента исходной последовательности. Напомним, что 
аналогичная возможность реализована и для ранее рассмотренных запро-
сов Where, TakeWhile, SkipWhile и Partition (см. п. 4.2). 
Запрос Numerate(from) позволяет снабдить элементы исходной последо-
вательности нумерацией, начиная от номера from (при отсутствии парамет-
ра from он считается равным 1). Полученная последовательность является 
последовательностью кортежей: 
var a := Range(12,15).Numerate; 
Write(a); // [(1,12),(2,13),(3,14),(4,15)] 
Запрос Tabulate упрощает формирование данных для табуляции функ-
ций (которая ранее обсуждалась нами в пунктах 1.3 и 3.5). С его помощью 
можно сформировать последовательность пар вида (x, f(x)), где аргументы x 
берутся из исходной последовательности, а функция f является параметром 
запроса: 
var a := Range(1,4).Tabulate(x -> Sqrt(x)); 
Write(a);
// [(1,1),(2,1.4142135623731),(3,1.73205080756888),(4,2)] 


76 
Как обычно, в конце пункта приведем решения нескольких задач 
группы LinqBegin, иллюстрирующие применение изученных запросов. 
В задаче LinqBegin33 требуется выделить из исходной целочисленной 
последовательности положительные числа, извлечь из них последние циф-
ры и удалить в полученной последовательности цифр все вхождения оди-
наковых цифр, кроме первого, после чего вывести оставшиеся цифры в ис-
ходном порядке: 
Task('LinqBegin33');
ReadSeqInteger.Where(e -> e > 0) 
.Select(e -> e mod 10).Distinct.WriteAll; 
В задаче LinqBegin38 требуется обработать элементы исходной цело-
численной последовательности следующим образом: если порядковый но-
мер элемента делится на 3 (3, 6, …), то этот элемент не включается в но-
вую последовательность; если остаток от деления порядкового номера на 3 
равен 1 (1, 4, …), то в новую последовательность добавляется удвоенное 
значение этого элемента; в противном случае (для элементов с номерами 2, 
5, …) элемент добавляется в новую последовательность без изменений.
При решении этой задачи следует использовать запросы с лямбда-
выражением, включающим индекс обрабатываемого элемента; кроме того, 
надо учитывать, что индекс элемента на 1 меньше его порядкового номера. 
Если переформулировать условие задачи в терминах индексов, то мы по-
лучим, что удваивать надо элементы, индекс которых делится на 3 без 
остатка, а удалять надо элементы, индекс которых дает при делении на 3 
остаток 2.
Поскольку при удалении части элементов индексы оставшихся эле-
ментов изменятся, следует вначале изменить (удвоить) нужные элементы с 
помощью запроса Select, а затем выполнить удаление лишних элементов: 
Task('LinqBegin38'); // Вариант 1 
ReadSeqInteger.Select((e, i) -> i mod 3 = 0 ? 2 * e : e) 
.Where((e, i) -> i mod 3 <> 2).WriteAll; 
Если воспользоваться тем фактом, что в запросе SelectMany с элемен-
том допустимо связывать пустую последовательность, то можно реализо-
вать решение задачи LinqBegin38, не требующее применения запроса 
Where: 
Task('LinqBegin38'); // Вариант 2 
ReadSeqInteger.SelectMany((e, i) -> i mod 3 = 0 ? Seq(2 * e) :
i mod 3 = 1 ? Seq(e) : SeqFill(0, 0)).WriteAll; 
Прокомментируем использованное в запросе лямбда-выражение. Если 
индекс элемента делится на 3, то возвращается одноэлементная последова-
тельность, содержащая удвоенное значение исходного элемента; в против-
ном случае, если индекс элемента при делении на 3 дает остаток 1, то воз-


Download 1.62 Mb.

Do'stlaringiz bilan baham:
1   ...   42   43   44   45   46   47   48   49   ...   71




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