使用Prolog获取列表中偶数的最长子序列
我想实现一个谓词 longest_even_sequence(X,Y)
,其中 X
是给定列表,Y
是返回最长子序列的列表偶数。例如,对于给定列表 2,4,6,3,5,2,2
我想返回 2,4,6
。
这是我尝试过的代码,但我不知道如何使其工作(我是 Prolog 的初学者)
longest_even_sequence([],[]).
longest_even_sequence([H|T],[R]):-
H mod 2 =:= 0,
longest_even_sequence(T,R1)
R is [H|R1] .
longest_even_sequence([H|T],[]):-
H mod 2 =\= 0,
longest_even_sequence(T,R2),
R2 is [].
I want to implement a predicate longest_even_sequence(X,Y)
where X
is the given list, Y
is a list that returns the longest subsequence of even number. For example for the given list 2,4,6,3,5,2,2
I want to return 2,4,6
.
Here is the code that I tried and I don't know how to make it work (I am a total beginner in Prolog)
longest_even_sequence([],[]).
longest_even_sequence([H|T],[R]):-
H mod 2 =:= 0,
longest_even_sequence(T,R1)
R is [H|R1] .
longest_even_sequence([H|T],[]):-
H mod 2 =\= 0,
longest_even_sequence(T,R2),
R2 is [].
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
老实说,这是一个对初学者来说相当不友好的任务,因为它没有直接指出 prolog 的优点,并且使用递归方法存在多个问题。
第一次尝试:添加一个参数。以基本的递归方式执行此操作需要您添加一个参数来保持当前的连续记录,以便将其与当前的最佳记录进行比较。这需要引入一个新的谓词,并且似乎是使用递归的最简单的初学者友好解决方案。为了不给自己太大压力,我使用 if-then-else
( ... -> ... ; ...)
来处理最大值选择。基本思想是遍历列表并收集第二个参数中的连续数据。一旦我达到奇数,我就会得到列表其余部分的最大偶数子序列 (longest_even_sequence(T,[],Rtmp)
) 并将其与当前的条纹进行比较 (LT > LR)。较大的列表将被复制到输出参数。一旦到达终点,我只需复制当前的连胜 (
longest_even_sequence([],R,R).
)。这一问题的潜在问题是连胜的顺序相反,因此您需要将其反转。另外,使用 if-then-else 也不是初学者水平。以连胜开始并以连胜结束是没有问题的。
使用 SWISH 进行测试:
只是为了好玩(是的,我是认真的),让我们用另一种更复杂且计算密集的方式进行测试:
测试:
那么会发生什么?首先生成
0
和输入列表长度之间的数字(使用range(N,0,Lin)
,修改后的代码来自 此处)按降序排列。然后创建一个包含N
(未知)元素的列表length(Out,N),
。然后输入列表In
被分成 3 部分,其中开始和结束并不有趣,但中间必须有N
元素,这是通过将其统一为Out
,这是一个包含N
元素的列表。该列表必须全部为偶数。如果成功,则跳过所有其他答案(!
,称为剪切,更高级的序言)。如果不成功,则测试下一个拟合子列表。如果没有适合长度N
的列表,则测试下一个较低的N
,直到最终达到N=0
。To be honest this is a rather beginner-unfriendly task because it doesn't point directly to the beauty of prolog and has multiple issues for using the recursive approach.
First try: adding an argument. Doing it in the basic recursive way requires you to add an argument to hold your current streak to compare it to your current best. This requires the introduction of a new predicate and seems to be the easiest beginner-friendly solution using recursion. For not stressing myself to hard I used the if-then-else
( ... -> ... ; ...)
to handle the maximum-chosing. Basic idea is going through the list and collecting a streak in the second argument. Once I hit an uneven number, I get the maximum even subsequence for the rest of the list (longest_even_sequence(T,[],Rtmp)
) and compare it with the current streak (LT > LR
). The larger list will be copied to the output argument. Once I reach the end, I just copy my current streak (longest_even_sequence([],R,R).
).Potential problem with this one is that the streak is in reverse order so you need to reverse it. Also using the if-then-else is not beginner-level. Staring with a streak and ending with a streak is no problem.
Tested with SWISH:
Just for fun (yeah, I mean it), let's do it another, more complex and computational intense way:
Test:
So what happens? At first a number between
0
and the length of the input list is generated (withrange(N,0,Lin)
, modfied code from here) in descending order. Then a list withN
(unknown) elements is createdlength(Out,N),
. Then the Input listIn
is split into 3 parts, where the beginning and the end is not interesting but the middle has to haveN
elements, which is enforced by unifying it withOut
, which is a list withN
elements. This list has to have all even numbers. If it succeeds, skip all other answers (!
, called a cut, more advanced prolog). If it doens't succeeds, the next fitting sublist is tested. If no list of lengthN
fits, then the next lowerN
is tested until you eventually hitN=0
.我现在已经对此进行了投票,但我想推荐使用foldl,但有一点不同:
longest_even_sequence([2,4,6,1,5,3,2,1], Result)
Result = [2, 4, 6 ]
I now this has been voted already, but I would like to recommend foldl, with a twist:
longest_even_sequence([2,4,6,1,5,3,2,1], Result)
Result = [2, 4, 6]