GNU Prolog - поиск по списку фактов - PullRequest
4 голосов
/ 15 декабря 2010

У меня, должно быть, пердит мозг или что-то в этом роде, но я просто не могу найти решение этой проблемы.

Если у вас есть список фактов, например:

%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 человек.Как ты сможешь это сделать?

Спасибо.

Ответы [ 2 ]

4 голосов
/ 15 декабря 2010

Попробуйте это для размера:

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 для обработки такого случая.

3 голосов
/ 15 декабря 2010

Немного более короткая версия превосходного ответа @ 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 (например, like x в логике первого порядка).

...