prolog - 列表的子列表 - 替代方法
prolog - sublist of list - alternative approach
我实现了获取列表子列表的功能,例如:
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
?
您可以使用 append/3 统一子列表,如下所示:
sublist(SubList, List):-
append(_, Tail, List),
append(SubList, _, Tail).
第一次调用 append/3
会将列表分成两部分(即从列表中删除一些 "leading" 项。
第二次调用 append/3
将检查 SubList 本身是否是 Tail 的子列表。
正如@false 所建议的那样,至少就地面而言,交换目标会更好,
sublist(SubList, List):-
append(SubList, _, Tail),
append(_, Tail, List).
还有一个 DCG 方法来解决这个问题:
substr(Sub) --> seq(_), seq(Sub), seq(_).
seq([]) --> [].
seq([Next|Rest]) --> [Next], seq(Rest).
您将使用的电话:
phrase(substr([1,2,4]), [1,2,3,4,5,1,2,4,6]).
您可以定义:
sublist(Sub, List) :-
phrase(substr(Sub), List).
所以你可以这样称呼它,sublist([1,2,4], [1,2,3,4,5,1,2,4,6]).
。
根据@mat 的建议:
substr(Sub) --> ..., seq(Sub), ... .
... --> [] | [_], ... .
是的,您可以有一个名为 ...
的谓词。 :)
根据@repeat 和@false 的建议,我将名称从 subseq
(子序列)更改为 substr
(子字符串),因为 "subsequence" 的含义包含非连续序列。
Maybe there is exists some predefined predicate
如果您的 Prolog append/2 来自库(列表):
sublist(S, L) :- append([_,S,_], L).
另一个相当紧凑的定义,在每个(我猜)Prolog 中都可用:
sublist(S, L) :- append(S, _, L).
sublist(S, [_|L]) :- sublist(S, L).
这是 Lurkers 的替代解决方案,速度稍快,
假设 S 的长度比 L 短得多,因此 phrase/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 而不仅仅是终端。
原始问题中的解决方案是有效的,正如已经说过的,请注意 "my_equals" 可以被 "append" 和 "sublist" 循环替换为另一个提供原始片段的追加列表。
然而,prolog 是(或者曾经是)关于人工智能的。任何人都可以立即回答 "no" 这个例子:
sublist([1,1,1,2], [1,1,1,1,1,1,1,1,1,1] ).
因为一个人,通过简单观察列表,推断出它的一些特征,比如没有“2”。
相反,这些提案在这种情况下确实效率低下。举个例子,在DNA分析领域,研究的是只有四个元素的长序列,这种算法是不适用的。
可以做一些简单的改变,objective先看最强的条件。例如:
/* 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.
看看 "analysis" 是如何决定最好寻找“2”的。
显然,这是一个非常简化的解决方案,在实际情况下可以做得更好 "analysis" 并且查找的模式必须更加灵活(建议仅限于原始 S 模式尾部的模式).
我实现了获取列表子列表的功能,例如:
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
?
您可以使用 append/3 统一子列表,如下所示:
sublist(SubList, List):-
append(_, Tail, List),
append(SubList, _, Tail).
第一次调用 append/3
会将列表分成两部分(即从列表中删除一些 "leading" 项。
第二次调用 append/3
将检查 SubList 本身是否是 Tail 的子列表。
正如@false 所建议的那样,至少就地面而言,交换目标会更好,
sublist(SubList, List):-
append(SubList, _, Tail),
append(_, Tail, List).
还有一个 DCG 方法来解决这个问题:
substr(Sub) --> seq(_), seq(Sub), seq(_).
seq([]) --> [].
seq([Next|Rest]) --> [Next], seq(Rest).
您将使用的电话:
phrase(substr([1,2,4]), [1,2,3,4,5,1,2,4,6]).
您可以定义:
sublist(Sub, List) :-
phrase(substr(Sub), List).
所以你可以这样称呼它,sublist([1,2,4], [1,2,3,4,5,1,2,4,6]).
。
根据@mat 的建议:
substr(Sub) --> ..., seq(Sub), ... .
... --> [] | [_], ... .
是的,您可以有一个名为 ...
的谓词。 :)
根据@repeat 和@false 的建议,我将名称从
subseq
(子序列)更改为 substr
(子字符串),因为 "subsequence" 的含义包含非连续序列。
Maybe there is exists some predefined predicate
如果您的 Prolog append/2 来自库(列表):
sublist(S, L) :- append([_,S,_], L).
另一个相当紧凑的定义,在每个(我猜)Prolog 中都可用:
sublist(S, L) :- append(S, _, L).
sublist(S, [_|L]) :- sublist(S, L).
这是 Lurkers 的替代解决方案,速度稍快, 假设 S 的长度比 L 短得多,因此 phrase/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 而不仅仅是终端。
原始问题中的解决方案是有效的,正如已经说过的,请注意 "my_equals" 可以被 "append" 和 "sublist" 循环替换为另一个提供原始片段的追加列表。
然而,prolog 是(或者曾经是)关于人工智能的。任何人都可以立即回答 "no" 这个例子:
sublist([1,1,1,2], [1,1,1,1,1,1,1,1,1,1] ).
因为一个人,通过简单观察列表,推断出它的一些特征,比如没有“2”。
相反,这些提案在这种情况下确实效率低下。举个例子,在DNA分析领域,研究的是只有四个元素的长序列,这种算法是不适用的。
可以做一些简单的改变,objective先看最强的条件。例如:
/* 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.
看看 "analysis" 是如何决定最好寻找“2”的。
显然,这是一个非常简化的解决方案,在实际情况下可以做得更好 "analysis" 并且查找的模式必须更加灵活(建议仅限于原始 S 模式尾部的模式).