Prolog 序言:比较两个列表,找出第一个列表中是否至少有一个成员存在于另一个列表中
为了进一步了解prolog(以及为了解决我的作业),我遇到了一种情况,我需要比较两个列表,找出是否至少有一个元素匹配…Prolog 序言:比较两个列表,找出第一个列表中是否至少有一个成员存在于另一个列表中,prolog,Prolog,为了进一步了解prolog(以及为了解决我的作业),我遇到了一种情况,我需要比较两个列表,找出是否至少有一个元素匹配… 下面是我想做的一个例子: ?-match([a,b,c],[x,y,z]). no. ?-match([a,b,c],[x,y,b]). yes. 到目前为止,我的解决方案是: compare_list([],[]). compare_list([],_). compare_list([L1Head|L1Tail],List2):- member(L1Head,Li
下面是我想做的一个例子:
?-match([a,b,c],[x,y,z]).
no.
?-match([a,b,c],[x,y,b]).
yes.
到目前为止,我的解决方案是:
compare_list([],[]).
compare_list([],_).
compare_list([L1Head|L1Tail],List2):-
member(L1Head,List2),
compare_list(L1Tail,List2).
但是当列表1的所有成员都出现在列表2中时,这个解决方案会给出一个true
请大家,不要认为我在作业上作弊,问题要复杂得多,我只是停留在这一点上,需要帮助才能走出这个棘手的角落。。。否则,整个任务都是我自己完成的 我将对您所做的尝试进行评论,虽然很接近,但还不够:
compare_list([],[]).
compare_list([],_).
compare_list/2
的第一个子句表示空列表中至少有一个元素。第二个表示空列表在任何其他列表中至少有一个元素。所以第一条是多余的(第二条已经涵盖了它)。您是否希望这是真的(空列表在任何其他列表中都有一个元素)取决于您。因为空列表没有成员,所以可能会认为这是一个失败案例(因此,不被声明为true),但如果您愿意,可以通过定义将其称为true。但是,一旦正确定义了谓词,它将在递归情况下导致一些问题,因为减少到[]
将变为true,最终可能会发现任何列表中都有元素(oops!)。我把这两个条款分开,认为这个案子失败了。
compare_list([L1Head|L1Tail], List2):-
member(L1Head, List2),
compare_list(L1Tail, List2).
这表示第一个列表在第二个列表中有一个元素,如果:(1)列表的头部是第二个列表的成员,(2)第一个列表的尾部在第二个列表中有一个元素。这听起来合乎逻辑吗?如果您仔细考虑了这一点,如果没有额外的compare\u list/2
子句,那么只有当第一个列表的每个元素都是第二个列表的成员时,这一点才是正确的,正如您所观察到的
最后,您缺少第一个列表的头不是第二个列表的成员的情况。这不一定是失败的,因为第一个列表的尾部可能在第二个列表中有一个成员,即使第一个元素(head)不是成员。使用示例谓词匹配/2。解决方案非常简单,只需递归遍历List1(在左侧),并通过memberchk/2谓词检查头部是否属于List2。使用memberchk/2的原因是它只成功一次(即,回溯时不可重新执行),这是“至少一个”条件的状态。如果List1为空,则谓词将失败 代码:
match([Head|Tail], List2):-
memberchk(Head,List2).
match([_|Tail],List2):-
match(Tail,List2).
| ?- match([a,b,c],[x,y,z]).
no
| ?- match([a,b,c],[x,y,b]).
yes
| ?- match([a,b,c],[]).
no
| ?- match([],[x,y,b]).
no
示例:
match([Head|Tail], List2):-
memberchk(Head,List2).
match([_|Tail],List2):-
match(Tail,List2).
| ?- match([a,b,c],[x,y,z]).
no
| ?- match([a,b,c],[x,y,b]).
yes
| ?- match([a,b,c],[]).
no
| ?- match([],[x,y,b]).
no
您的问题可以使用更简单的内置程序解决
match(L1,L2) :- member(E,L1),member(E,L2). % full join
如果你真的只对“至少一个”解决方案感兴趣,那么就加上讨厌的削减
match(L1,L2) :- member(E,L1),memberchk(E,L2),!. % really, just the first!
另一种方法是使用nth0谓词
match(L1, L2) :-
nth0(_, L1, SharedItem),
nth0(_, L2, SharedItem).
第一个nth0表示“是否有一个L1列表项具有索引“uz”(即不关心它是否位于列表中的第一、第二等位置),其名称为变量SharedItem
第二个nth0对L2也有相同的作用
但是好的技巧在于统一。通过在两个n上使用相同的变量名SharedItem,prolog将继续遍历列表,直到两个列表中都有相同的项
一如既往,“trace.”谓词是您最好的朋友。请在调用上面的命令之前运行它,以查看prolog在后台执行的操作:
[trace] ?- match([a,b,c],[x,y,b]).
Call: (6) match([a, b, c], [x, y, b]) ? creep
Call: (7) lists:nth0(_G1965, [a, b, c], _G1967) ? creep
Exit: (7) lists:nth0(0, [a, b, c], a) ? creep
Call: (7) lists:nth0(_G1968, [x, y, b], a) ? creep
Fail: (7) lists:nth0(_G1968, [x, y, b], a) ? creep
Redo: (7) lists:nth0(_G1968, [a, b, c], _G1970) ? creep
Exit: (7) lists:nth0(1, [a, b, c], b) ? creep
Call: (7) lists:nth0(_G1968, [x, y, b], b) ? creep
Exit: (7) lists:nth0(2, [x, y, b], b) ? creep
Exit: (6) match([a, b, c], [x, y, b]) ? creep
true .
所以“外部”循环是L1。它首先尝试L1(a)的索引0,然后当它在L2中找不到它时,它会重做(第一个nth0),但这次是使用索引1(b)你的学校允许你在你的作业中寻求帮助吗?大多数学校不认为这是一种学术冒犯。@克里斯蒂安:这不是我的主要任务……它更复杂,我只是陷在这个小问题上…这是一个相当基本的列表处理问题。我建议查一些例子。列表处理的les(如此处:)请看一看序言文档中的
member/2
谓词。@实际上,我已经研究了这个问题,我也基于member/2提出了一个解决方案,但它只成功地实现了第一个列表中的所有项目也出现在第二个列表中……如果您愿意,我可以向您展示我的解决方案?如果您希望获得帮助,它实际上是req在指导原则中,你展示了你的尝试。因此,是的,编辑你的问题并添加你尝试的代码。好的,但是我如何迭代第一个列表中的所有元素以确定第二个列表中是否有匹配项?与你在尝试中所做的相同。你在尾部进行递归调用。最终,它将导致[]
这种情况应视为失败(如我的回答所示)但我已经这样做了,它并没有像我希望的那样工作,它只在所有成员都匹配时才给我true。我如何在获得第一个匹配并返回true时立即停止?请仔细阅读我上面的答案。问题是,递归调用与没有它的情况下应该成功的情况在同一个子句中(如我在回答中所述).在这种情况下,如果第一个列表的头不是第二个列表的成员,您只需要一个递归调用,这是您没有涉及的情况。我知道我不应该在这里感谢您,但是,非常感谢!最后一件事,请您标记我的问题,因为当我发布问题时,一些糟糕的词语选择和一些我的错误不完整的信息导致有人认为我试图在作业中作弊,但随后我更新并解释了情况。您不需要明确的匹配([],\u:-失败。
取消该子句即可。:)