Должно быть, у меня пукнул мозг или что-то в этом роде, но я просто не могу найти решение этой проблемы.
Если у вас есть список фактов, таких как:
%country(country, population, capital)
country(sweden, 8823, stockholm).
country(usa, 221000, washington).
country(france, 56000, paris).
country(denmark, 3400, copenhagen).
%city(city, country, population)
city(lund, sweden, 88).
city(new_york, usa, 5000).
city(paris, usa, 1).
city(copenhagen, denmark, 1200).
city(aarhus, denmark, 330).
city(odense, denmark, 120).
city(stockholm, sweden, 350).
city(washington, usa, 3400).
city(paris, france, 2000).
city(marseilles, france, 1000).
Я хочу найти второй по величине населенный город, которым в данном случае будет Вашингтон, США, с населением 3400 человек. Как бы вы смогли это сделать?
Спасибо.
Ответ 1 · рейтинг 3 · Fred Foo
Чуть более короткая версия отличного ответа @sharky:
second_largest_city(Second) :-
setof(Size/City, Country^city(City,Country,Size), Cities),
append(_, [_/Second, _], Cities).
setof объединяет findall и sort. Мы собираем Size/City пар, чтобы они автоматически сортировались по размеру. Конструкция X^Goal вводит экзистенциально квантифицированную переменную X (например, x в логике первого порядка).
Ответ 2 · рейтинг 4 · Community
Попробуйте это для размера:
second_largest_city(City) :-
findall(Size, city(_, _, Size), Sizes),
sort(Sizes, SortedSizes),
append(_, [Size2, _], SortedSizes),
city(City, _Country, Size2).
Объяснение. findall/3 находит размеры всех city/3 фактов, которые отсортированы в возрастающем порядке по sort/2 с удалением дубликатов. Вызов шаблона append/3 соответствует разделению отсортированного списка SortedSizes на две части; список любого размера (_) и остаток длины два ([Size2, _]) - это связывает переменную Size2 со вторым по величине размером города из city/3 фактов. Наконец, все города с этим размером расположены среди city/3 фактов и привязаны к выходным данным.
Примечание. Обычно это не будет работать должным образом, если ваша встроенная функция для sort/2 не удаляет дубликаты, потому что это оставляет открытой возможность того, что city/3 фактов с более чем одним равный максимум вернет только максимум (самый большой). Эта реализация, использующая append/3 для поиска предпоследнего элемента отсортированного списка размеров, также предполагает sort/2 отсортированные числа в порядке возрастания.
Кроме того, наконец, обратите внимание, что это полностью потерпит неудачу, если имеется менее двух city/3 фактов - но это, вероятно, нормально, учитывая, что предикат ищет "второй по величине" город, и, строго говоря, не было бы ни одного, если бы не было действительно как минимум два города в БД с разными размерами. Если это проблема, вы можете просто написать больше предложений для second_largest_city/1, чтобы справиться с таким случаем.