【问题标题】:How to show only one result in prolog?如何在序言中只显示一个结果?
【发布时间】:2016-05-12 22:58:07
【问题描述】:

数据:

%flight(FID, Start, Destination, Company, Seats).
%------------------------------------------------------
flight(1, 'Paris', 'Berlin', 'Lufthansa', 210).
flight(2, 'Frankfurt', 'Dubai', 'Lufthansa', 400).
flight(3, 'Rome', 'Barcelona', 'Eurowings', 350).

我想了解所有拥有超过 200 个座位的航班的公司。但每家公司只能退回一次。

我试过了:

q1(Company) :- flight(_, _, _, Company, S), S > 200.

但这会返回两次汉莎航空。我试过了:

q1(Company) :- flight(_, _, _, Company, S), S > 200,!.

但这在汉莎航空首次返回后退出。我想我必须将条件包装在子查询中:

q1(Company) :- flight(_, _, _, Company, S), q12(S).
q12(S) :- flight(_, _, _, _, S), S > 200,!.

但这在第一次返回后也退出了。知道如何使用 cut 返回只匹配一次的公司吗?

FID 是主键,我只能使用 . , + =

【问题讨论】:

  • 首先,删除!/0:它破坏了程序的预期含义。然后使用setof/3 收集所有公司,如下所示:?- setof(Company, q1(Company), Cs). 这将为您提供一个没有重复的排序列表。如果你愿意,你可以列举公司,例如?- setof(C, q1(C), Cs), member(C, Cs).
  • @mat 我不允许使用 setof,只能使用 ", . ! \+ ="
  • 这是一个奇怪的要求。你至少可以使用sort/2吗?否则,您需要本着 SQL 左连接或类似的精神做一个奇怪的把戏。
  • @Boris 你能告诉我这个奇怪的把戏吗?
  • 我得考虑一下。您可以尝试在 SQL 标记上寻找灵感 :) 或者也许有人已经为您准备好了答案。

标签: prolog


【解决方案1】:

正如我在 cmets 中所说,一种方法是使用 setof/3 获取排序后的结果列表没有重复,例如:

?- setof(C, q1(C), Cs).

这是删除冗余解决方案的推荐方法。您可以列举这样的解决方案,例如:

?- setof(C, q1(C), Cs), member(C, Cs).

建议观众自行决定其余部分...


对于不熟练的教练可能强加给您的脑损伤情况,还有几种方法可以解决此问题。例如,使用setof/3 获取所有出现在您的数据库中的公司,这是一种低效且非常不习惯的方法:

公司(Cs):- 公司_([],CS)。 公司_(Cs0,Cs):- (飞行(_,_,_,C,_), \+ 成员chk(C, Cs0) -> 公司_([C|Cs0], Cs) ; Cs0 = Cs )。

我没有胃口继续说下去,所以我只是给你一个提示:你只需要插入一个目标来解决你的任务。我希望你的老师对这个“解决方案”感到满意。

【讨论】:

  • 这使用memberchk/2,这可能也不是“允许的”:) 但请参阅其他答案以获取替代方法。
  • 此版本中的所有内容都可以仅使用所示的原语轻松表达。例如,memberchk/2 和 if-then-else 可以用!/0 表示。这些都是逻辑hacking的例子,而不是逻辑programming,所以我不想在这个方向上展示更多。
  • 为什么还是memberchk/2
  • 我什至无法...阅读 member/2(\+)/1。最好使用if_/3
【解决方案2】:

这里的关键是唯一 ID。你原来的问题是:

哪些公司的航班座位数超过 200 个?

查询很明显:

?- flight(_,_,_,C,S), S > 200.
C = 'Lufthansa',
S = 210 ;
C = 'Lufthansa',
S = 400 ;
C = 'Eurowings',
S = 350.

现在,由于 ID 是唯一的,因此组内将有一个航班具有相同的公司和座位 > 200,其 ID 最高(或最低)。因此,您可以将您的问题重新表述为:

在同一公司的航班组中,哪些航班的座位数超过 200 个且 ID 最高?

或者,为了更接近我们在 Prolog 中提出查询的方式,

给定一个带有 ID、公司和座位的航班,座位数必须超过 200,并且不能有来自同一公司的具有更高 ID 的其他航班。

?- flight(ID,_,_,C,S), S > 200, \+ ( flight(IDX,_,_,C,_), IDX > ID ).
ID = 2,
C = 'Lufthansa',
S = 400 ;
ID = 3,
C = 'Eurowings',
S = 350.

如果将此查询放在谓词中,则可以避免报告 ID 和实际座位数。

顺便说一句,这种方法是由this answer 提供的一个有点相关的问题(无耻的自我推销)。我真的不记得我的想法是从哪里来的:我敢肯定我不是自己想出来的。如果有人可以在 Stackoverflow 或其他地方找到好的参考资料,请发表评论。

【讨论】:

  • 感谢您让我走上了正轨。顺便说一句,我找到了另一个使用 cut 运算符似乎正确的解决方案。我把它放在我的问题中。
  • @artworkadshi 你确定你需要那个剪辑吗?如果删除它会发生什么?
猜你喜欢
  • 2017-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 2021-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多