【问题标题】:How to check if a list is a non-empty sublist of another list in Prolog如何检查列表是否是Prolog中另一个列表的非空子列表
【发布时间】:2017-11-07 02:18:19
【问题描述】:

我正在尝试创建一个included_list(X,Y) 术语来检查 X 是否是 Y 的非空子列表。

我已经用它来检查元素是否存在于 Y 列表中

check_x(X,[X|Tail]).
check_x(X,[Head|Tail]):- check_x(X,Tail).

还有附加项

append([], L, L).
append([X | L1], L2, [X | L3]) :- append(L1, L2, L3).

创建一个列表,以便程序完成

included_list([HeadX|TailX],[HeadX|TailX]).

但我在处理我试图通过“追加”创建的新空列表时遇到问题(我想创建一个空列表来添加已确认存在于两个列表中的元素。)

我找到了这个

sublist1( [], _ ).
sublist1( [X|XS], [X|XSS] ) :- sublist1( XS, XSS ).
sublist1( [X|XS], [_|XSS] ) :- sublist1( [X|XS], XSS ).

但它在 sublist([],[1,2,3,4) 上变为 true

【问题讨论】:

  • 如果是考虑订单的子列表?或顺序无关紧要。 ?
  • 您能否详细说明“但我在处理我试图通过“追加”创建的新空列表时遇到问题”?处理什么?您如何创建空列表以及将其用于什么?
  • @user2520215 这确实适用于空子列表。
  • @LeleDumbo 我想创建一个空列表来添加确认存在于两个列表中的元素。

标签: prolog sublist


【解决方案1】:

由于您正在寻找一个非连续子列表有序子集,并且不想包含空列表,那么:

sub_list([X], [X|_]).
sub_list([X], [Y|T]) :-
    X \== Y,
    sub_list([X], T).
sub_list([X,Y|T1], [X|T2]) :-
    sub_list([Y|T1], T2).
sub_list([X,Y|T1], [Z|T2]) :-
    X \== Z,
    sub_list([X,Y|T1], T2).

一些结果:

| ?- sub_list([1,4], [1,2,3,4]).

true ? a

no
| ?- sub_list(X, [1,2,3]).

X = [1] ? a

X = [2]

X = [3]

X = [1,2]

X = [1,3]

X = [1,2,3]

X = [2,3]

(2 ms) no
| ?- sub_list([1,X], [1,2,3,4]).

X = 2 ? a

X = 3

X = 4

(2 ms) no

请注意,它不仅会告诉您一个列表是否是另一个列表的子列表,它还会回答更一般的问题,例如,L 的子列表是什么?在谓词中使用,它可以在这种情况下删除可能的有效解决方案。所以这个解决方案避免了使用 cut 的原因。

解释:

这个想法是生成一组规则来定义子列表是什么,并尝试这样做而不是程序性或命令性的。上述子句可以理解为:

  1. [X] 是列表 [X|_] 的子列表
  2. 如果XY 不同并且[X] 是列表T 的子列表,则[X] 是列表[Y|T] 的子列表。 XY 不同的条件可防止此规则与规则 #1 重叠,并通过避免不必要的递归大大减少执行查询所需的推理次数。
  3. 如果[Y|T1]T2 的子列表,则[X,Y|T1][X|T2] 的子列表。 [X,Y|T1] 形式确保列表至少有两个元素,以免与规则 #1 重叠(这可能导致任何单个解决方案重复多次)。
  4. 如果XZ 不同并且[X,Y|T1]T2 的子列表,则[X,Y|T1][Z|T2] 的子列表。 [X,Y|T1] 形式确保列表至少有两个元素,以免与规则#2 重叠,XZ 不同的条件防止此规则与规则#3 重叠(这可能导致任何单个解决方案重复多次),并通过避免不必要的递归大大减少执行查询所需的推理次数。

【讨论】:

  • 您能解释一下您的代码是如何工作的吗?似乎工作正常:)
  • 感谢您的解释。我是 prolog 的新手,我很难理解递归过程。您是否在代码中编辑了任何内容?
  • @Crownless - 仅供参考,我认为 user2520215 的答案现在同样有效,而且更简洁。
  • 没错,但我真的很喜欢你的解释。
  • 最后两条规则可以像:sub_list([X|T1], [X|T2]) :- sub_list(T1, T2). sub_list([X|T1], [Z|T2]) :- X \== Z, sub_list([X|T1], T2).
【解决方案2】:

这是你要做的:

mysublist(L,L1):- sublist(L,L1), notnull(L).

notnull(X):-X\=[].

sublist( [], _ ).
sublist( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
sublist( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).

从中获取参考: Prolog - first list is sublist of second list? 我只是预先添加了条件来检查它是否为空。

希望这会有所帮助。

【讨论】:

  • 这似乎是我的问题的答案:)
  • 如果您能向我解释这段代码以及它是如何工作的,我将不胜感激。 :)
  • mysublist(S, [1,2,3]) 返回 false,因此它表示 [1,2,3] 没有子列表,S
  • @user2520215 能否像 lurker 一样为最后 3 个子列表规则添加解释?
  • 宁可:mysublist(L,L1) :- L = [_|_], sublist(L,L1). 并且名称子列表最不幸,请改用subsequence
【解决方案3】:

如果订单很重要。示例 [1,2,3][1,2,3,4] 的子列表,但 [1,3,2] 不是。

你可以做这样的事情。

sublist([],L).
sublist([X|L1],[X|L2]):- sublist(L1,L2)

【讨论】:

  • 顺序很重要。但是您的代码不适用于 [1,4] 和 [1,2,3,4]
  • @Crownless 好的,检查我的答案,你可以使用类似的东西。如果第一个列表是第二个列表的子列表,它将返回 True。
  • 这仅适用于子列表从第一个位置开始的情况。换句话说,`sublist([1,2,3],[0,1,2,3]) 会失败。
  • @schrobe 我问订单是否重要。
  • 那么,那不是我的情况,
【解决方案4】:

我会使用附加:

sublist(X, []) :-
    is_list(X).


sublist(L, [X | Rest]) :-
    append(_, [X|T], L),
    sublist(T, Rest).

【讨论】:

    【解决方案5】:

    基本上,如果 M 存在于 L 中,我们可以通过在其背面和/或前面附加一些东西来检查 M 是否是 L 的子列表。

    append([], Y, Y).
    append([X|XS],YS,[X|Res]) :- append(XS, YS, Res).
    
    sublist(_, []).
    sublist(L, M) :- append(R, _, L), append(_, M, R).
    

    【讨论】:

      猜你喜欢
      • 2021-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-08
      相关资源
      最近更新 更多