我必须有一个大脑放屁或其他东西,但我似乎无法找到解决方案。
如果您有列表事实,例如:
%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人。你怎么能这样做?
感谢。
答案 0 :(得分:4)
尝试这个尺寸:
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
分成两部分;任意大小的列表(_
)和长度为2的余数([Size2, _]
) - 这会将变量Size2
与city/3
个事实中的第二大城市大小绑定。最后,具有此大小的所有城市都位于city/3
个事实之中,并且在输出上受到约束。
注意:如果sort/2
的内置功能不删除重复内容,则一般无法正常运行,因为这样可以解决问题city/3
具有多个相等最大值的事实将仅返回最大值(最大值)。使用append/3
来查找排序的大小列表的倒数第二个元素的此实现也假设sort/2
排序的数字按升序排列。
另外,最后请注意,如果少于两个city/3
事实,这将彻底失败 - 但这可能没问题,因为谓词寻找“第二大”城市,严格来说不会除非确实在DB中有至少两个城市的大小不同,否则不会成为一个城市。如果这是一个问题,您可以为second_largest_city/1
编写更多条款来处理这种情况。
答案 1 :(得分:3)
@ 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 )。