List 根据给定索引和大量元素的列表创建子列表。序言

List 根据给定索引和大量元素的列表创建子列表。序言,list,indexing,prolog,element,sublist,List,Indexing,Prolog,Element,Sublist,我试图解决一个简单的序言问题,但我不能解决它。从一个列表中,需要创建一个子列表(给定索引I),然后从I开始创建下一个元素(给定为N)。如果索引大于列表长度,则子列表将为空。如果N(元素数)大于列表中的其余元素,我将从I获取所有元素,直到结束 ?- sublist([a,b,c,d],4,4,L) L=[d] 这里,我得到了作业的一部分,我可以从索引I中得到,接下来的元素N。现在我问一下作业中的其他部分: 1) 当I(索引)长于列表长度时,我必须在子列表中获得一个空列表 ?- su

我试图解决一个简单的序言问题,但我不能解决它。从一个列表中,需要创建一个子列表(给定索引I),然后从I开始创建下一个元素(给定为N)。如果索引大于列表长度,则子列表将为空。如果N(元素数)大于列表中的其余元素,我将从I获取所有元素,直到结束

?- sublist([a,b,c,d],4,4,L)

L=[d]      
这里,我得到了作业的一部分,我可以从索引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).
这是一个好条款。它表示从列表
[X | |)
中获取的长度为1的子列表是
[X]

sublist([X|Xs], 1, K, [X|Ys]) :-
    K > 1, 
    K1 is K - 1,
    sublist(Xs, 1, K1, Ys).
这也是一个好条款。它表示从1开始的长度
K
子列表取自
[X | Xs]
X
开始,并且有一个从1开始的长度
K-1
子列表的尾部
Ys

sublist([_|Xs], I, K, Ys) :-
    I > 1, 
    I1 is I - 1,
    K1 is K - 1,
    sublist(Xs, I1, K1, Ys).
这一条款有一个问题。如果您有一个列表
[|Xs]
,并且希望从
I
开始获取长度为
K
的子列表(对于
I
大于1),则从
I-1
位置开始获取长度为
K-1
的子列表。问题是:为什么子列表现在需要长度
K-1
?本条的目的是将问题简化为处理起始索引
1
,然后让第二条处理其余部分

然后在您对所需行为的定义中,您有:如果N(元素数)大于列表中的其余元素,我将从I获取所有元素,直到最后。这一概念目前不在任何条款中。基本情况是当前的第一个子句,它特别要求长度为1才能生成长度为1的列表。您需要另一个base case子句来处理第一个列表为空但
K
可能仍然是任意值的情况:

sublist([], ?, _, ?).
只需在
中填入符合逻辑的内容即可。:)

这里有一个解决方案(尽管这可能不是你教授想要的):

这是一种方法,让Prolog的内置程序为您完成工作

这里有另一种不使用任何内置项的方法。这一个使用一个helper谓词,它简单地将列表拆分为指定长度的前缀和后缀,由剩余的内容组成

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!

只是为了说明像/3这样的不确定性内置项有多大帮助

sublist(List, From, Count, SubList) :-
    findall(E, (nth1(I, List, E), I >= From, I < From + Count), SubList).
我想看看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].

这看起来是一个很好的开始。需要考虑的一个问题是你的第三个从句:你正在递减
K
,你需要问自己为什么在这种情况下这样做,以及(如果你真的认为应该)在什么条件下这样做。此外,如果您的条件是如果
N
太大,您需要一个“截断”答案,那么当输入列表为空时,您可能需要另一个(或不同的)基本case子句来处理该情况。@mbrach:您的注释看起来是愿意学习的学生的最佳答案。。。为什么不把它转换成一个答案呢?谢谢@capelical,我会这么做的。@user3006475,我的答案是否为你提供了足够的帮助来解决其余的问题?是的,谢谢,但我没有prolog方面的经验,我无法解决它。我需要写下我描述的两个案例…我认为这不是很难…但我不能解决它…但是谢谢你的解释…我更好地理解它第一个似乎大错特错:
?-子列表([a,b,c,d],2,2,L)。L=[a,b]。
?-子列表([a,b,c,d],2,3,L)。错@capelical:修复了打字错误。+1是使用内置单行解决方案的大师。非常好。:)这一个是我想要的工作…重点是我不能使用内置的…多可怜的@姆布拉奇:谢谢!我认为你的详细解释很好。@user3006475:谢谢!当然,你可以不用内置的,但请注意,这是一个内置的…最后我得到了它…现在是我想要的工作,这个解释帮助很大@用户3006475太好了!我在测试基本用例时遇到了一些问题。在我在SWI prolog的问题中描述的第一个案例中,我得到了一个true作为答案,而不是空列表。在第二种情况下,我理解得很好,但在我的答案中,我得到了另一个东西:代替这个答案,我得到这个答案。。。你能帮我解决这个问题吗?@user3006475,在你更新的答案中,你仍然缺少我建议的附加基本情况:
子列表([],?,-)。
(在这里你决定应该是什么
)。换句话说,您需要一个案例来处理输入列表为空时发生的情况。如果你需要更多的帮助,请告诉我。因此,完成后,将有4个子句,而不仅仅是3个。@user3006475这是因为规则
子列表([],I,u,L)。
不会实例化
L
I
。他们是独生子女,该条款不是你所说的有效条款。它当前表示,“如果输入列表为空,则不要使用
I
,并且输出是未定义的列表,
L
”。要为
找出正确的内容,请提出以下问题:如果输入列表为空,则
L
应该是什么?
I
应该是什么(或者这有关系吗?它能仅仅是
?)?
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].
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].