Prolog程序创建具有第一个重复元素的列表

时间:2019-04-03 18:18:58

标签: prolog run-length-encoding

我需要实现此功能:

cod_first(X, L, Lrem, Lfront). 

Lfront包含X开头的L的所有副本,包括XLrem是其余元素的列表。

我尝试使用append来实现它,但是我在Prolog中是个新手,我有点迷茫。

该程序的预期输出如下:

?- cod_first(1, [1, 1, 2, 3], Lrem, Lfront) 
Lrem = [2, 3],
Lfront = [1, 1, 1];
false.

?- cod_first(1, [2, 3, 4], Lrem, Lfront)
Lrem = [2, 3, 4],
Lfront = [1];
false.

更新:我发现此函数将相同的元素打包到列表中:

pack([], []).
pack([X], [[X]]).
pack([X, X| L], [[X| Xs]| R]) :-
    pack([X| L], [Xs| R]).
pack([X, Y| L], [[X]| R]) :-
    X \= Y,
    pack([Y| L], R).

我认为此功能可以适应我正在寻找的功能,有帮助吗?

1 个答案:

答案 0 :(得分:1)

首先让我们检查找到的代码!我将考虑从最短的列表开始的 all 列表进行测试:

?- N=N, length(Xs,N), pack(Xs, Xss).
   N = 0, Xs = [], Xss = []
;  N = 1, Xs = [_A], Xss = [[_A]]
;  N = 2, Xs = [_A,_A], Xss = [[_A,_A]]
;  N = 3, Xs = [_A,_A,_A], Xss = [[_A,_A,_A]]
;  N = 4, Xs = [_A,_A,_A,_A], Xss = [[_A,_A,_A,_A]]
;  ...

因此,根据此查询,您的代码仅适用于所有元素都相同的列表。实际上,目标X \= Y对此负责。使用dif(X, Y)更好地表达不平等。有了这个小小的变化,我们得到:

 ?- N=N, length(Xs,N), pack(Xs, Xss).
    N = 0, Xs = [], Xss = []
 ;  N = 1, Xs = [_A], Xss = [[_A]]
 ;  N = 2, Xs = [_A,_A], Xss = [[_A,_A]]
 ;  N = 2, Xs = [_A,_B], Xss = [[_A],[_B]], dif(_A,_B)
 ;  N = 3, Xs = [_A,_A,_A], Xss = [[_A,_A,_A]]
 ;  N = 3, Xs = [_A,_A,_B], Xss = [[_A,_A],[_B]], dif(_A,_B)
 ;  N = 3, Xs = [_A,_B,_B], Xss = [[_A],[_B,_B]],  dif(_A,_B)
 ;  N = 3, Xs = [_A,_B,_C], Xss = [[_A],[_B],[_C]], dif(_A,_B), dif(_B,_C)
 ;  N = 4, Xs = [_A,_A,_A,_A], Xss = [[_A,_A,_A,_A]]
 ;  ...

现在,我们可以获得所有解决方案。让我们考虑一下N = 2的两个答案。第一个说法是,对于Xs的元素都相等,Xss仅包含一个元素。第二种说法是,当Xs的元素不同时,它们将显示在Xss的单独元素中。请注意dif(_A,_B),可确保仅选择不同的术语。

但是,您只对单个这样的拆分感兴趣:

cod_first(X, [], [], [X]).
cod_first(X, [X|Es], Lrem, [X|Xs]) :-
   cod_first(X, Es, Lrem, Xs).
cod_first(X, [E|Es], [E|Es], [X]) :-
   dif(X,E).

?- N=N, length(Xs, N), cod_first(X, Xs, Lrem, Lfront).
   N = 0, Xs = [], Lrem = [], Lfront = [X]
;  N = 1, Xs = [X], Lrem = [], Lfront = [X,X]
;  N = 1, Xs = [_A], Lrem = [_A], Lfront = [X], dif(_A,X)
;  N = 2, Xs = [X,X], Lrem = [], Lfront = [X,X,X]
;  N = 2, Xs = [X,_A], Lrem = [_A], Lfront = [X,X], dif(_A,X)
;  N = 2, Xs = [_A,_B], Lrem = [_A,_B], Lfront = [X], dif(_A,X)
;  N = 3, Xs = [X,X,X], Lrem = [], Lfront = [X,X,X,X]
;  N = 3, Xs = [X,X,_A], Lrem = [_A], Lfront = [X,X,X], dif(_A,X)
;  N = 3, Xs = [X,_A,_B], Lrem = [_A,_B], Lfront = [X,X], dif(_A,X)
;  N = 3, Xs = [_A,_B,_C], Lrem = [_A,_B,_C], Lfront = [X], dif(_A,X)
;  N = 4, Xs = [X,X,X,X], Lrem = [], Lfront = [X,X,X,X,X]
;  ...

这里是我更喜欢使用library(reif)的另一个版本 对于 SICStusSWI

cod_first2(X, Es, Lrem, [X|Xs]) :-
   cod_first2i(Es, X, Xs, Lrem).

cod_first2i([], _, [], []).
cod_first2i([E|Es], X, Xs0, Ys) :-
   if_( E = X
      , ( Xs0 = [X|Xs], cod_first2i(Es, X, Xs, Ys) )
      , ( Xs0 = [], Ys = [E|Es] )
      ).

这效率更高,但是给出的答案却完全相同。