【问题标题】:prolog - sublist of list - alternative approachprolog - 列表的子列表 - 替代方法
【发布时间】:2016-05-29 23:01:19
【问题描述】:

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

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

【问题讨论】:

  • my_equals(L1, L2) 将等同于 append(L1, _, L2)
  • my_equals 更好的名字是prefix_of
  • @lurker,如果我理解正确,请告诉我。实际上,append(L1, _, L2) 检查L1(整个)是否是L2 的前缀。类似地,append(_, L1, L2) 检查L1(整个)是否是L2 的后缀。是吗?
  • @HaskellFun 你明白了 :)
  • 虽然我可能会更改术语,而不是说 checks 我会说 succeeds。所以,append(_, L1, L2) 成功 如果L1L2 的后缀。

标签: prolog dcg


【解决方案1】:

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

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

第一次调用 append/3 会将 List 分成两部分(即从 List 中删除一些“领先”项目。 对append/3 的第二次调用将检查 SubList 本身是否是 Tail 的子列表。

正如@false 所暗示的那样,至少在基本条件下,交换目标会更好,

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

【讨论】:

  • 交换目标不是更好吗?
  • 如何使用Tail ?左边没有这个变量?
  • 我认为第二个实现存在终止问题。
  • @HaskellFun 谓词append/3 是一个很好地定义关系的谓词。在 Prolog 中,关系可以“生成”结果,因此 append(Sublist, _, Tail) 对于具有变量的 Tail 的值将成功。作为一个说明性练习,在 Prolog 提示符下,尝试查询 append([a,b,c], _, Tail) 并查看您得到什么样的结果。 :)
  • @lurker:是的,如果是用于生成解决方案的过程,我更喜欢第一个实现(在我看来)。
【解决方案2】:

还有一种解决问题的 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(子字符串),因为“子序列”的含义包含非连续序列。

【讨论】:

  • ...//0 在这里会很方便:..., list(Sub), ...
  • 不错! ... --> [] | [_], ... ;-)
  • @mat oy,我有时会很啰嗦。 :)
  • @false 是的,你是对的。 seq//1 更好。谢谢。
  • @repeat 我在这个disseration 中注意到,在第 6 页,它说,“Es 必须是Es0子序列”,如连续,所以也许我最初的用法是在好公司。 :)
【解决方案3】:

这是 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,而不仅仅是终端。

【讨论】:

    【解决方案4】:

    也许存在一些预定义的谓词

    如果您的 Prolog 有来自库(列表)的 append/2:

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

    另一个相当紧凑的定义,在每个(我猜)Prolog 中都有:

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

    【讨论】:

      【解决方案5】:

      如前所述,原始问题中的解决方案是有效的,请注意“my_equals”可以被“append”和“sublist”循环替换为另一个附加提供原始列表切片的循环。

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

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

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

      相反,在这种情况下,这些建议确实效率低下。例如,在DNA分析领域,只研究4个元素的长序列,这种算法是不适用的。

      可以进行一些简单的更改,目的是首先寻找最强大的条件。举例:

      /* 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 模式尾部的模式)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-03
        相关资源
        最近更新 更多