prolog - 列表子列表 - 替代方法

时间:2016-05-13 11:30:57

标签: prolog dcg

我实现了获取列表子列表的函数,例如:

sublist([1,2,4], [1,2,3,4,5,1,2,4,6]).
true

sublist([1,2,4], [1,2,3,4,5,1,2,6]). false 看看我的解决方案:

my_equals([], _).
my_equals([H1|T1], [H1|T2]) :- my_equals(T1, T2).

sublist([], _).
sublist(L1, [H2|T2]) :- my_equals(L1, [H2|T2]); sublist(L1, T2).  

你能给我另一个解决方案吗?也许存在一些预定义的谓词my_equals

5 个答案:

答案 0 :(得分:4)

您可以使用append/3统一子列表,如下所示:

sublist(SubList, List):-
  append(_, Tail, List),
  append(SubList, _, Tail).

第一次拨打append/3会将List拆分为两部分(即从列表中删除部分"前导"项目。 对append/3的第二次调用将检查SubList本身是否为Tail的子列表。

正如@ false&f; s表明,至少在地面条件下交换目标会更好,

sublist(SubList, List):-
  append(SubList, _, Tail),
  append(_, Tail, List).

答案 1 :(得分:4)

There's also a DCG approach to the problem:

substr(Sub) --> seq(_), seq(Sub), seq(_).

seq([]) --> [].
seq([Next|Rest]) --> [Next], seq(Rest).

Which you would call with:

phrase(substr([1,2,4]), [1,2,3,4,5,1,2,4,6]).

You can define:

sublist(Sub, List) :-
    phrase(substr(Sub), List).

So you could call it by, sublist([1,2,4], [1,2,3,4,5,1,2,4,6])..


Per @mat's suggestion:

substr(Sub) --> ..., seq(Sub), ... .

... --> [] | [_], ... .

Yes, you can have a predicate named .... :)


Per suggestions from @repeat and @false, I changed the name from subseq (subsequence) to substr (substring) since the meaning of "subsequence" embraces non-contiguous sequences.

答案 2 :(得分:2)

这是Lurkers的另一种解决方案,它稍快一点, 假设S的长度比L短得多,因此短语/ 3 DCG 翻译时间可以忽略不计:

sublist(S, L) :-
     phrase((..., S), L, _).

如果S = [X1,..,Xn],它会将DCG转换为匹配I = [X1,..,Xn | O] 在执行之前,因此将my_equals / 2完全委托给Prolog 统一。以下是一个示例运行:

?- phrase((..., [a,b]), [a,c,a,b,a,c,a,b,a,c], X).
X = [a, c, a, b, a, c] ; 
X = [a, c] ; 
false.

再见

P.S。:也适用于其他模式S而不仅仅是终端。

答案 3 :(得分:0)

  

可能存在一些预定义的谓词

如果您的Prolog已从库(列表)附加/ 2:

sublist(S, L) :- append([_,S,_], L).

另一个相当紧凑的定义,可用于每个(我猜)Prolog那里:

sublist(S, L) :- append(S, _, L).
sublist(S, [_|L]) :- sublist(S, L).

答案 4 :(得分:0)

原始问题中的解决方案是有效的,正如已经说过的那样,“my_equals”可以被“append”和“sublist”循环替换为另一个附加提供原始列表的切片。

然而,prolog是(或者是)关于人工智能。任何人都可以立即回答“不”这个例子:

sublist([1,1,1,2], [1,1,1,1,1,1,1,1,1,1] ).

因为一个人,通过对列表的简单观察,推断出它的某些特征,就像没有“2”一样。

相反,这个提案在这种情况下效率很低。例如,在DNA分析领域,只研究了四个元素的长序列,这种算法不适用。

可以进行一些简单的更改,目标是首先查看最强的条件。例如:

/* common( X, Y, C, QX, QY ) => X=C+QX, Y=C+QY */ 
common( [H|S2], [H|L2], [H|C2], DS, DL ) :- !,
     common( S2, L2, C2, DS, DL ).
common( S, L, [], S, L ).

sublist( S, L ) :-
  sublist( [], S, L ). 

sublist( P, Q, L ) :- /* S=P+Q */ 
  writeln( Q ),
  length( P, N ),
  length( PD, N ), /* PD is P with all unbound */
  append( PD, T, L ), /* L=PD+T */ 
  common( Q, T, C, Q2, _DL ), /* S=P+C+Q2; L=PD+C+_DL */
  analysis( L, P, PD, C, Q2 ).  

analysis( _L, P, P, _C, [] ) :- !. /* found sublist */

analysis( [_|L2], P, _PD, C, [] ) :- !,
  sublist( P, C, L2 ).

analysis( [_|L2], P, _PD, C, Q2 ) :-
  append( P, C, P2 ),
  sublist( P2, Q2, L2 ).

让我们试一试:

?- sublist([1,1,1,2], [1,1,1,1,1,1,1,1,1,1]).
[1,1,1,2]
[2]
[2]
[2]
[2]
[2]
[2]
[2]
[2]
false.

看看“分析”如何决定更好地寻找“2”。

显然,这是一个强烈简化的解决方案,在实际情况下,可以进行更好的“分析”,找到的模式必须更灵活(提案仅限于原始S模式尾部的模式)。