【问题标题】:GNU Prolog - searching a list of factsGNU Prolog - 搜索事实列表
【发布时间】:2010-12-15 03:57:41
【问题描述】:

我一定是脑子里放屁什么的,但我似乎找不到解决办法。

如果您有一个列表事实,例如:

%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 人。你怎么能做到这一点?

谢谢。

【问题讨论】:

  • 你会如何寻找最大的城市?

标签: prolog rules


【解决方案1】:

试试这个尺寸:

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 内置删除重复项,这通常不会正常工作,因为这会留下@ 987654333@ 具有多个相等最大值的事实将仅返回最大值(最大)。此实现使用append/3 查找大小排序列表的倒数第二个元素,还假定sort/2 将数字按升序排列。

最后,请注意,如果city/3 事实少于两个,这将彻底失败——但这可能没问题,因为谓词寻找“第二大”城市,严格来说不会除非在 DB 中确实存在至少两个不同规模的城市,否则应为其中之一。如果这是一个问题,您可以为second_largest_city/1 编写更多子句来处理这种情况。

【讨论】:

  • sort/2 不在 ISO Prolog 中,但它在 Edinburgh Prolog 中,具有您所描述的语义,这是 ISO 标准的基础。支持 ISO 的 Prolog 有一个带有任何其他语义的内置 sort/2 会很奇怪:我猜没有。
  • @Charles:SWI、YAP 和 SICStus 的 sort/2 具有预期的语义。对此答案 +1。
【解决方案2】:

@sharky 出色答案的略短版本:

second_largest_city(Second) :-
    setof(Size/City, Country^city(City,Country,Size), Cities),
    append(_, [_/Second, _], Cities).

setof 结合了 findallsort。我们收集Size/City 对,因此它们会自动按大小排序。构造X^Goal 引入了一个存在量化变量X(如一阶逻辑中的∃x)。

【讨论】:

  • 稍短的版本 来自 larsmans 的短版本的单行代码: second_largest_city(Second):- setof(Size/City, Country^city(City,Country,Size), [, _ /秒|])。
  • @gusbro:我们想要Cities 的倒数第二个成员,而不是第二个。
  • 哎呀,你是对的。那将是 second_largest_city(Second):- setof(RSize/City, Country^Size^(city(City,Country,Size), RSize is -Size), [, _/Second|]) .这次可能不值得单行...
  • 称我为老式的,但我什至不认为超过 80 个字符的单行线;)
  • @larsmans;我曾考虑过setof/3,但忘记了它在生成集合时使用sort/2 对解决方案进行了排序!无论如何,我更喜欢这个解决方案 - 它不仅更简洁,而且更高效(另外,我学到了一些东西......)+1
猜你喜欢
  • 2012-05-24
  • 1970-01-01
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
相关资源
最近更新 更多