我正在尝试解决一个简单的序言问题,但我无法解决它。从列表中需要创建一个给定索引I的子列表,然后从I给出下一个给定为N的元素。如果索引大于列表长度,我将得到子列表为空。如果N(元素的数量)大于列表中的其余元素,我将从I获得所有元素直到结束。
在这里,我得到了一部分作业,我可以从索引I得到下一个元素N.现在我询问作业中的其他部分:
1)当I
(索引)长于列表长度时,我必须在子列表中获得一个空列表。
?- sublist([a,b,c,d],5,2,L)
L=[]
2)当N
(下一个元素)大于我们休息的元素数量时,我需要从该位置获取所有元素直到结束。
?- sublist([a,b,c,d],4,4,L)
L=[d]
我已经拥有的代码是下一个代码,这个代码正在运行:
sublist([X|_],1,1,[X]).
sublist([],_,_,[]).% I use this one for the case bases
sublist([X|Xs],1,K,[X|Ys]):-
K>1,
K1 is K-1,
sublist(Xs,1,K1,Ys).
sublist([_|Xs],I,K,Ys):-
I > 1,
I1 is I-1,
sublist(Xs,I1,K,Ys).
答案 0 :(得分:2)
sublist([X|_], 1, 1, [X]).
这是一个很好的条款。它表示从[X|_]
列表中选择的从1开始的长度为1的子列表为[X]
。
sublist([X|Xs], 1, K, [X|Ys]) :-
K > 1,
K1 is K - 1,
sublist(Xs, 1, K1, Ys).
这也是一个很好的条款。它表示从K
开始的长度为[X|Xs]
的子列表以X
开头,并且尾部Ys
是来自K-1
的子列表从1开始的第一个列表(Xs
)的尾部。
sublist([_|Xs], I, K, Ys) :-
I > 1,
I1 is I - 1,
K1 is K - 1,
sublist(Xs, I1, K1, Ys).
此条款有问题。如果您有一个列表[_|Xs]
,并且想要从K
(I
大于1)开始,请选择长度为I
的子列表,则会获取长度为{{的子列表1}}从它的尾部开始,位置K-1
。问题是:为什么子列表现在需要长度为I-1
?此子句的目的应该是将问题减少到您处理起始索引的情况K-1
,然后让第二个条款处理其余部分。
然后在您对期望行为的定义中,您有:如果N(元素数量)大于列表中其余元素,我将从I获取所有元素直到结束。目前这个概念不属于任何条款。基本情况当前是您的第一个子句,特别需要长度为1来生成长度为1的列表。您需要另一个基本案例子句来处理第一个列表为空但1
可能仍为任何值的情况:
K
只需填写sublist([], ?, _, ?).
符合逻辑的内容即可。 :)
答案 1 :(得分:2)
只是为了展示像nth1 / 3这样的不确定性内置组合如何帮助......
sublist(List, From, Count, SubList) :-
findall(E, (nth1(I, List, E), I >= From, I < From + Count), SubList).
编辑一条说明,说这个“一个班轮”实际上比制作的子列表/ 4效率低得多。
实际上,
2 ?- N=1000000,length(L,N),time(sublist(L,N,1,V)).
% 3,000,014 inferences, 2.129 CPU in 2.134 seconds (100% CPU, 1409024 Lips)
N = 1000000,
L = [_G28, _G31, _G34, _G37, _G40, _G43, _G46, _G49, _G52|...],
V = [_G3000104].
3 ?- N=1000000,length(L,N),time(sublist(L,1,1,V)).
% 4,000,012 inferences, 2.549 CPU in 2.553 seconds (100% CPU, 1569076 Lips)
N = 1000000,
L = [_G28, _G31, _G34, _G37, _G40, _G43, _G46, _G49, _G52|...],
V = [_G3000104].
我将看看在findall'谓词中是否可以解决这个问题,但这不太可能。这个更好:
sublist(List, From, Count, SubList) :-
To is From + Count - 1,
findall(E, (between(From, To, I), nth1(I, List, E)), SubList).
18 ?- N=1000000,length(L,N),time(sublist(L,3,3,V)).
% 28 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 201437 Lips)
N = 1000000,
L = [_G682, _G685, _G688, _G691, _G694, _G697, _G700, _G703, _G706|...],
V = [_G3000762, _G3000759, _G3000756].
答案 2 :(得分:0)
这是一个解决方案(虽然它可能不是你教授想要的):
sublist( Xs , Offset , Count , Ys ) :- %
length(Prefix,Offset ) , % construct a list of variables of length 'offset'
length(Ys,Count) , % construct a list of variables of length 'count'
append(Prefix,Suffix,Xs) , % strip the first first 'offset' items from the source list ,
append(Ys,_,Suffix) % extract the first 'count' items from what's left.
. % easy!
这是一种方法,让Prolog的内置插件为您完成工作。
这是另一种不使用任何内置插件的方法。这个使用一个帮助器谓词,它只是简单地将列表拆分为指定长度的前缀,以及后缀,由剩余的任何内容组成。
sublist( Xs , Offset , Count , Ys ) :-
split(Xs,Offset,_,X1) , % extract the first 'offset' items from the lsit and toss them
split(X1,Count,Ys,_) % extract the first 'count' items from the remainder to get the result.
.
split( [] , 0 , [] , [] ) . % splitting a zero-length prefix from an empty list yields a zero-length prefix and a zero length suffix.
split( [X|Xs] , 0 , [] , [X|Xs] ) . % splitting a zero-length prefix from a non-empty list yields a zero-length prefix and the non-empty list.
split( [X|Xs] , N , [X|Ps] , Qs ) :- % Otherwise...
N > 0 , % - if the count is positive
N1 is N-1 , % - we decrement count
split( Xs , N1 , Ps , Qs ) % - and recurse down, prepending the head of the source list to the prefix
. % Easy!