Prolog程序从列表中删除每个第n个元素

时间:2014-05-03 01:49:07

标签: list prolog

你能帮我解决一下吗?

  

编写一个三元谓词delete_nth,删除列表中的每个第n个元素。

样品运行:

?‐ delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e] ;
false
?‐ delete_nth([a,b,c,d,e,f],1,L).
L = [] ;
false
?‐ delete_nth([a,b,c,d,e,f],0,L).
false

我试过了:

listnum([],0).
listnum([_|L],N) :-
   listnum(L,N1),
   N is N1+1.

delete_nth([],_,_).
delete_nth([X|L],C,L1) :- 
   listnum(L,S),
   Num is S+1,
   (  C>0
   -> Y is round(Num/C),Y=0
   -> delete_nth(L,C,L1)
   ;  delete_nth(L,C,[X|L1])
   ).

5 个答案:

答案 0 :(得分:4)

我的稍微奢侈的变种:

delete_nth(L, N, R) :-
    N > 0, % Added to conform "?‐ delete_nth([a,b,c,d,e,f],0,L). false"
    ( N1 is N - 1, length(Begin, N1), append(Begin, [_|Rest], L) ->
        delete_nth(Rest, N, RestNew), append(Begin, RestNew, R)
    ;
        R = L
    ).

答案 1 :(得分:3)

让我们使用!为了多功能性和其他很多理由:

:- use_module(library(clpfd)).

我们根据if_/3(#>=)/3定义delete_nth/3

delete_nth(Xs,N,Ys) :-
   N #> 0,
   every_tmp_nth_deleted(Xs,0,N,Ys).

every_tmp_nth_deleted([]    ,_ ,_,[] ).     % internal auxiliary predicate
every_tmp_nth_deleted([X|Xs],N0,N,Ys0) :-
   N1 is N0+1,
   if_(N1 #>= N,
       (N2 =  0, Ys0 =    Ys ),
       (N2 = N1, Ys0 = [X|Ys])),
   every_tmp_nth_deleted(Xs,N2,N,Ys).

示例查询:

?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],2,Ys).
Ys = [1,3,5,7,9,11,13,15]                 % succeeds deterministically

好的, little 更通用的东西怎么样?

?- delete_nth([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],N,Ys).
  N  =  1     , Ys = []
; N  =  2     , Ys = [1,  3,  5,  7,  9,   11,   13,   15]
; N  =  3     , Ys = [1,2,  4,5,  7,8,  10,11,   13,14   ]
; N  =  4     , Ys = [1,2,3,  5,6,7,  9,10,11,   13,14,15]
; N  =  5     , Ys = [1,2,3,4,  6,7,8,9,   11,12,13,14   ]
; N  =  6     , Ys = [1,2,3,4,5,  7,8,9,10,11,   13,14,15]
; N  =  7     , Ys = [1,2,3,4,5,6,  8,9,10,11,12,13,   15]
; N  =  8     , Ys = [1,2,3,4,5,6,7,  9,10,11,12,13,14,15]
; N  =  9     , Ys = [1,2,3,4,5,6,7,8,  10,11,12,13,14,15]
; N  = 10     , Ys = [1,2,3,4,5,6,7,8,9,   11,12,13,14,15]
; N  = 11     , Ys = [1,2,3,4,5,6,7,8,9,10,   12,13,14,15]
; N  = 12     , Ys = [1,2,3,4,5,6,7,8,9,10,11,   13,14,15]
; N  = 13     , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,   14,15]
; N  = 14     , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,   15]
; N  = 15     , Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14   ]
; N in 16..sup, Ys = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].

答案 2 :(得分:2)

编辑,纠正@CapelliC指出的错误,其中谓词在N = 0时成功。

我可以看到你的解决方案在哪里,但在这种情况下你不必费心这么多算术。我们可以通过从N重复向下计数直到列表为空来删除第N个元素。首先,快速说明风格:

如果您使用空格,换行符和正确放置括号,您可以帮助您的读者解析您的代码。您的最后一个条款在这种形式下更具可读性:

delete_nth([X|L], C, L1):-
    listnum(L, S),
    Num is S+1,
    C>0 -> Y is round(Num/C),
    Y=0 -> delete_nth(L, C, L1)
    ; delete_nth(L, C, [X|L1]).

现在查看你的代码,我不确定你是否打算写

( C>0 -> ( Y is round(Num/C), 
           Y=0 -> delete_nth(L, C, L1) )
; delete_nth(L, C, [X|L1])
).

或者如果你的意思是

C>0 -> Y is round(Num/C), 
( Y=0 -> delete_nth(L, C, L1)
; delete_nth(L, C, [X|L1])
).

或者你可能在第二个条件之前错过了;?无论如何,我建议采用另一种方法......

这看起来像是辅助谓词的工作!

通常,我们只需要一个简单的关系来构成一个查询,但解析查询并得到一个答案所需的计算过程需要一个更复杂的关系。在这些情况下,“说起来容易做起来难”。

我对此问题的解决方法如下:为了删除每个第n个元素,我们从N开始并向下计数到1.每次我们从N递减值时,我们将元素从原始列表移动到列表我们要保留的元素。当我们到达1时,我们丢弃原始列表中的元素,并再次从N开始倒计时。正如您所看到的,为了询问“放弃Kept的每个N元素导致的列表List是什么?”我们只需要三个变量。但我回答这个问题,还需要另一个变量来跟踪从N到1的倒计时,因为每次我们从List开始,我们都需要问“什么是{{ 1}}?”一旦我们达到1,我们就需要能够记住Count的原始值。

因此,我提供的解决方案依赖于辅助的4位谓词来进行计算,将3位谓词作为“前端”,即作为用于提出问题的谓词。

N

答案 3 :(得分:2)

请遵循病理学家的指导性答案和解释(+1)。我只是在解决方案上发布自己的赌注,因为?‐ delete_nth([a,b,c,d,e,f],0,L).的同上解决方案存在问题。

delete_nth(L,C,R) :-
    delete_nth(L,C,1,R).

delete_nth([],_,_,[]).
delete_nth([_|T],C,C,T1) :- !, delete_nth(T,C,1,T1).
delete_nth([H|T],N,C,[H|T1]) :- C<N, C1 is C+1, delete_nth(T,N,C1,T1).

产量

1 ?- delete_nth([a,b,c,d,e,f],2,L).
L = [a, c, e].

2 ?- delete_nth([a,b,c,d,e,f],1,L).
L = [].

3 ?- delete_nth([a,b,c,d,e,f],0,L).
false.

一个小问题(?):这段代码是确定性的,而明显发布的样本不是(你必须输入';'才能得到假结尾)。删除剪切将产生相同的行为。

一个有趣的 - imho - 一个班轮变体:

delete_nth(L,C,R) :- findall(E, (nth1(I,L,E),I mod C =\= 0), R).

但必须排除C == 0,以避免

ERROR: mod/2: Arithmetic: evaluation error: `zero_divisor'

答案 4 :(得分:1)

另一种方法,跟进@ user3598120最初的冲动来计算不受欢迎的第N个元素,并受到@Sergey Dymchenko玩具的启发。它使用exclude/3删除基于1的索引处的所有元素,该索引是N

的倍数
delete_nth(List, N, Kept) :-
    N > 0, 
    exclude(index_multiple_of(N, List), List, Kept).

index_multiple_of(N, List, Element) :-
    nth1(Index, List, Element),
    0 is Index mod N.
相关问题