Списки. Предикаты высших порядков
7.5. Предикаты сортировки списка
Операцию сортировки списка выполняют предикаты sort и sortBy класса list. Сортировка выполняется в соответствии с алгоритмом слияния. По умолчанию список сортируется по возрастанию элементов:
L = sort([3, 6, 5, 1, 7, 8]).
Для упорядочения списка по убыванию элементов используется предикат sort/2:
L = sort([3, 6, 5, 1, 7, 8], descending()).
Предикат sortBy выполняет сортировку в соответствии с заданным критерием. Например, при вызове
L = sortBy({(X, Y) = compare(X mod 3, Y mod 3)}, [3, 5, 7, 6, 1])
элементы списка будут упорядочены по возрастанию в соответствии со значением их остатка от деления на 3.
Критерий сортировки можно определить как в виде анонимного предиката (см. выше), так и в виде отдельного предиката (см. листинг 7.8).
class predicates
comp : comparator{tuple{string, integer}}.
clauses
comp(tuple(X, N), tuple(Y, N)) = compare(X, Y):- !.
comp(tuple(_, N), tuple(_, K)) = compare(N, K).
run():-
write(list::sortBy(comp, [tuple("Маша", 18), tuple("Даша", 19),
tuple("Глаша", 18), tuple("Паша", 17)])),
_ = readLine().
Пример
7.8.
Сортировка по заданному критерию
Список содержит сведения об именах и возрасте группы студентов. В результате применения предиката sortBy список упорядочивается по возрасту, а если возраст одинаковый, то по именам, в соответствии с лексикографическим порядком.
В следующей программе приведены примеры использования предикатов второго порядка класса list — forAll/2, fold/3, removeDuplicatesBy/2, maximumBy/2 и decompose/2.
open core, console, list
class predicates
comp : comparator{tuple{string, integer}}.
clauses
comp(tuple(_, N), tuple(_, K)) = compare(N, K). % по возрасту
run():-
L = [tuple("Маша", 18), tuple("Даша", 19),
tuple("Глаша", 18), tuple("Паша", 17)],
% вывод элементов списка
forAll(L, {(tuple(X, N)):- write(X, " - ", N), nl}), nl,
% суммарный возраст студентов
write(fold(L, {(tuple(_, K), S) = K + S}, 0)), nl,
% удаление студентов того же возраста, остаются по одному
write(removeDuplicatesBy(comp, L)), nl,
% самый старший по возрасту студент
write(maximumBy(comp, L)), nl,
% разбиение на группы по возрасту
write(decompose(L, {(tuple(_, Age)) = Age})),
_ = readLine().
Пример
7.9.
Предикаты высших порядков
Упражнения
- По заданному списку проверьте, образуют ли его элементы арифметическую прогрессию.
- Определите операцию возвращения из списка слов всех слов-палиндромов. Для разбиения слов на списки символов используйте предикат string::toCharList/1.
- Определите операцию симметрической разности множеств, представленных списками.
-
Определите операцию циклического сдвига элементов списка на заданное количество элементов
- вправо;
- влево.
- Сгенерируйте все перестановки списка, содержащие заданный подсписок.
- Сенерируйте все перестановки с повторениями, состоящие из заданного числа элементов, для данного множества элементов.
- Для заданного множества сгенерируйте сочетания с повторениями, состоящие из заданного числа элементов.
- Определите критерий сортировки элементов списка, состоящего из троек вида tuple(X, Y, Z), в которых хранятся имена (X), отчества (Y) и фамилии (Z) людей. Список должен быть упорядочен по фамилиям, при одинаковых фамилиях — по именам, при одинаковых именах и фамилиях — по отчествам.
- Найдите разбиение на классы эквивалентности множества элементов неотрицательных целых чисел. Два элементы эквивалентны, если они имеют одинаковые остатки при делении на n.