将列表切割成较小的列表

时间:2013-12-30 14:48:48

标签: list recursion prolog sublist

我目前正在处理99 Prolog问题列表http://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/,问题是18。它声明:

  

给定两个索引IK,切片是包含原始列表的I'和K'元素之间的元素的列表(包括两个限制)。开始使用1计算元素。

     

示例查询:?- slice([a,b,c,d,e,f,g,h,i,k],3,7,L).
  预期结果:L = [c,d,e,f,g]

我看过给定的解决方案,但我的问题是,是否有人能够找出解决方案错误的原因?这是我的代码:

chop([H|_],_,End,End,[H]).
chop([_|L],Start,End,Count,Out) :-
    (Count < Start),
    N is Count + 1,
    chop(L,Start,End,N,Out).
chop([H|L],Start,End,Count,[H|Out]) :-
    (Count >= Start; Count < End),
    N is Count + 1,
    chop(L,Start,End,N,Out).

slice(L,Start,End,Out) :-
    (Start =< End),
    Count is 1,
    chop(L,Start,End,Count,Out).

我的思路是:如果迭代'Count'中的元素在两个给定限制之间,则添加到列表中,如果没有则继续。作为示例输出,用于呼叫:

?- slice([a,b,c,d,e],2,3,X).

我得到了输出:

X = [b,c] ? ;
X = [b,c] ? ;
X = [a,b,c] ? ;
X = [a,b,c] ? ;

致电:

?- slice([a,b,c,d,e],3,3,X).
X = [c] ? ;
X = [b,c] ? ;
X = [a,c] ? ;
X = [a,b,c] ? ;

第一个给定的列表是正确的但是一切都出错了;我尝试过使用痕迹,但令人难以置信。

2 个答案:

答案 0 :(得分:2)

我们定义slice/4基于append/3length/2,由Prolog Prologue定义:

slice(AsBsCs,P,Q,Bs) :-
   append(AsBs,_Cs,AsBsCs),
   append(As  , Bs,AsBs  ),
   length([_|As],P),
   length( AsBs ,Q).

OP给出的示例查询:

?- slice([a,b,c,d,e,f,g,h,i,k],3,7,Xs).
Xs = [c,d,e,f,g] ;
false.

让我们像这样概括上面的查询:

?- slice([a,b,c,d,e,f,g,h,i,k],P,7,Xs).
  P = 1, Xs = [a,b,c,d,e,f,g]
; P = 2, Xs =   [b,c,d,e,f,g]
; P = 3, Xs =     [c,d,e,f,g]
; P = 4, Xs =       [d,e,f,g]
; P = 5, Xs =         [e,f,g]
; P = 6, Xs =           [f,g]
; P = 7, Xs =             [g]
; P = 8, Xs =              [] 
; false.

如何推广不同的方式?

?- slice([a,b,c,d,e,f,g,h,i,k],3,Q,Xs).
; Q =  2, Xs = []
; Q =  3, Xs = [c]
; Q =  4, Xs = [c,d]
; Q =  5, Xs = [c,d,e]
; Q =  6, Xs = [c,d,e,f]
; Q =  7, Xs = [c,d,e,f,g]
; Q =  8, Xs = [c,d,e,f,g,h]
; Q =  9, Xs = [c,d,e,f,g,h,i]
; Q = 10, Xs = [c,d,e,f,g,h,i,k]
; false.

最后,我们运行一个查询,它是两者的概括:

?- slice([a,b,c,d,e,f,g,h,i,k],P,Q,Xs).
  P =  1, Q =  0, Xs = []
; P =  1, Q =  1, Xs = [a]
; P =  2, Q =  1, Xs = []
; P =  1, Q =  2, Xs = [a,b]
; P =  2, Q =  2, Xs = [b]
; P =  3, Q =  2, Xs = []
; P =  1, Q =  3, Xs = [a,b,c]
; P =  2, Q =  3, Xs = [b,c]
; P =  3, Q =  3, Xs = [c]
; P =  4, Q =  3, Xs = []
; P =  1, Q =  4, Xs = [a,b,c,d]
; P =  2, Q =  4, Xs = [b,c,d]
; P =  3, Q =  4, Xs = [c,d]
; P =  4, Q =  4, Xs = [d]
; P =  5, Q =  4, Xs = []
; P =  1, Q =  5, Xs = [a,b,c,d,e]
; P =  2, Q =  5, Xs = [b,c,d,e]
; P =  3, Q =  5, Xs = [c,d,e]
; P =  4, Q =  5, Xs = [d,e]
; P =  5, Q =  5, Xs = [e]
; P =  6, Q =  5, Xs = []
; P =  1, Q =  6, Xs = [a,b,c,d,e,f]
; P =  2, Q =  6, Xs = [b,c,d,e,f]
; P =  3, Q =  6, Xs = [c,d,e,f]
; P =  4, Q =  6, Xs = [d,e,f]
; P =  5, Q =  6, Xs = [e,f]
; P =  6, Q =  6, Xs = [f]
; P =  7, Q =  6, Xs = []
; P =  1, Q =  7, Xs = [a,b,c,d,e,f,g]
; P =  2, Q =  7, Xs = [b,c,d,e,f,g]
; P =  3, Q =  7, Xs = [c,d,e,f,g]
; P =  4, Q =  7, Xs = [d,e,f,g]
; P =  5, Q =  7, Xs = [e,f,g]
; P =  6, Q =  7, Xs = [f,g]
; P =  7, Q =  7, Xs = [g]
; P =  8, Q =  7, Xs = []
; P =  1, Q =  8, Xs = [a,b,c,d,e,f,g,h]
; P =  2, Q =  8, Xs = [b,c,d,e,f,g,h]
; P =  3, Q =  8, Xs = [c,d,e,f,g,h]
; P =  4, Q =  8, Xs = [d,e,f,g,h]
; P =  5, Q =  8, Xs = [e,f,g,h]
; P =  6, Q =  8, Xs = [f,g,h]
; P =  7, Q =  8, Xs = [g,h]
; P =  8, Q =  8, Xs = [h]
; P =  9, Q =  8, Xs = []
; P =  1, Q =  9, Xs = [a,b,c,d,e,f,g,h,i]
; P =  2, Q =  9, Xs = [b,c,d,e,f,g,h,i]
; P =  3, Q =  9, Xs = [c,d,e,f,g,h,i]
; P =  4, Q =  9, Xs = [d,e,f,g,h,i]
; P =  5, Q =  9, Xs = [e,f,g,h,i]
; P =  6, Q =  9, Xs = [f,g,h,i]
; P =  7, Q =  9, Xs = [g,h,i]
; P =  8, Q =  9, Xs = [h,i]
; P =  9, Q =  9, Xs = [i]
; P = 10, Q =  9, Xs = []
; P =  1, Q = 10, Xs = [a,b,c,d,e,f,g,h,i,k]
; P =  2, Q = 10, Xs = [b,c,d,e,f,g,h,i,k]
; P =  3, Q = 10, Xs = [c,d,e,f,g,h,i,k]
; P =  4, Q = 10, Xs = [d,e,f,g,h,i,k]
; P =  5, Q = 10, Xs = [e,f,g,h,i,k]
; P =  6, Q = 10, Xs = [f,g,h,i,k]
; P =  7, Q = 10, Xs = [g,h,i,k]
; P =  8, Q = 10, Xs = [h,i,k]
; P =  9, Q = 10, Xs = [i,k]
; P = 10, Q = 10, Xs = [k]
; P = 11, Q = 10, Xs = []
; false.

答案 1 :(得分:0)

你遇到的问题是你的规则并不相互排斥 与你的第二条规则匹配的一切

chop([_|L],Start,End,Count,Out) :-

也会与您的第三条规则相匹配

chop([H|L],Start,End,Count,[H|Out]) :-

这意味着一旦你找到了一个有效的答案,并试图找到更多,每个成功分支到第二个规则将导致第三个分支后面的第二个答案。 (因此附加的前置字母)

您可以通过在第二条规则末尾添加剪切来解决此问题

chop([_|L],Start,End,Count,Out) :-
  (Count < Start),
  N is Count + 1,
  chop(L,Start,End,N,Out),
  !.