在单独的列表中拆分列表

时间:2015-02-08 08:46:57

标签: prolog

我必须为我的列表定义更多约束。

我想将我的列表拆分为单独的列表。

示例:

List=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]]

我需要从主列表中获得三个列表:

[[_,0],[_,0],[_,0]] and [[_,0]] and [[2,0],[4,0]]

所以我总是需要一个带有[X,1]的术语之间的一组列表。

如果你能给我一个提示,那就太好了。不想要解决方案,只提示如何解决这个问题。

约克

3 个答案:

答案 0 :(得分:3)

目前尚不清楚"列表组"的含义。在您的示例中,您从符合[1,1]标准的[_,1]开始。那么一开始不应该有一个空列表吗?或许你的意思是这一切都从这样一个标记开始? 如果周围还有其他标记怎么办?

首先,您需要为标记元素定义标准。这适用于两种情况:当它适用时和不适用时,因此这是一个元素。

marker([_,1]).

nonmarker([_,C]) :-
   dif(1, C).

请注意,对于这些谓词,我们暗示的每个元素都[_,_]。你没有陈述,但它确实有意义。

split(Xs, As, Bs, Cs) :-
   phrase(three_seqs(As, Bs, Cs), Xs).

marker -->
   [E],
   {marker(E)}.

three_seqs(As, Bs, Cs) -->
   marker,
   all_seq(nonmarker, As),
   marker,
   all_seq(nonmarker, Bs),
   marker,
   all_seq(nonmarker, Cs).

有关all_seq//2的定义,请参阅this

代替marker,可以写all_seq(marker,[_])

答案 1 :(得分:3)

此实现尝试保留,而不会将列表项限制为[_,_],例如 @false's answer。 我可以看到强加上面的限制确实很有意义......我仍然想解除它 - 并且攻击更普遍的问题。

以下内容基于if_/3splitlistIf/3和已知谓词marker_truth/2marker_truth(M,T)M的“标记” - 标识为真值Ttruefalse)。

is_marker([_,1]).                      % non-reified

marker_truth([_,1],true).              % reified: variant #1
marker_truth(Xs,false) :-
   dif(Xs,[_,1]).

够简单!我们在查询中一起尝试splitlistIf/3marker_truth/2

?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]], 
   splitlistIf(marker_truth,Ls,Pss).
Ls  = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [     [[_A,0],[_B,0],[_C,0]],    [[_D,0]],    [[2,0],[4,0]]] ? ; % OK
Ls  = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [     [[_A,0],[_B,0],[_C,0]],    [[_D,0],[9,1],[2,0],[4,0]]],
prolog:dif([9,1],[_E,1])                                           ? ; % BAD
%% query aborted (6 other BAD answers omitted)

D'哦!

上面显示的第二个答案肯定是我们想要的。 显然,splitlistIf/3 应该在那时分割Ls, 目标is_marker([9,1])成功。它没有。相反,我们得到了一个冻结的dif/2目标的答案,永远不会被唤醒,因为它正在等待匿名变量_E的实例化。

猜猜谁应该受到指责! marker_truth/2的第二个条款:

marker_truth(Xs,false) :- dif(Xs,[_,1]).       % BAD

我们能做些什么呢?使用我们自己的不等式谓词,它不会冻结永远不会被实例化的变量:

marker_truth(Xs,Truth) :-                      % variant #2
   freeze(Xs, marker_truth__1(Xs,Truth)).

marker_truth__1(Xs,Truth) :-
   (  Xs = [_|Xs0]
   -> freeze(Xs0, marker_truth__2(Xs0,Truth))
   ;  Truth = false
   ).

marker_truth__2(Xs,Truth) :-
   (  Xs = [X|Xs0]
   -> when((nonvar(X);nonvar(Xs0)), marker_truth__3(X,Xs0,Truth))
   ;  Truth = false
   ).

marker_truth__3(X,Xs0,Truth) :- % X or Xs0 have become nonvar
   (  nonvar(X)
   -> (  X == 1 
      -> freeze(Xs0,(Xs0 == [] -> Truth = true ; Truth = false))
      ;  Truth = false
      )
   ;  Xs0 == []
   -> freeze(X,(X == 1 -> Truth = true ; Truth = false))
   ;  Truth = false
   ).

所有这些代码,用于表达is_marker([_,1])的安全逻辑否定? 难看!

让我们看看它是否(至少)帮助了上面的查询(给出了这么多无用答案的那个)!

?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
   splitlistIf(marker_truth,Ls,Pss).
Ls  = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [[     [_A,0],[_B,0],[_C,0]],    [[_D,0]],    [[2,0],[4,0]]] ? ;
no

有效!然而,当考虑所需的编码工作时,很明显无论是代码生成方案还是代码生成方案

编辑2015-05-25

以上实施dif/2 有些有效,但还有很多不足之处。考虑:

marker_truth/2

这个答案不是我们想要得到的。为了了解原因,我们来看看integer_truth/2的可比性使用的答案:

?- marker_truth(M,Truth).                   % most general use
freeze(M, marker_truth__1(M, Truth)).

最常见的两个答案--- 那是一个具体化的谓词应该如何表现!

让我们相应地重新编码?- integer_truth(I,Truth). % most general use Truth = true, freeze(I, integer(I)) ; Truth = false, freeze(I, \+integer(I)).

marker_truth/2

让我们使用marker_truth(Xs,Truth) :- subsumes_term([_,1],Xs), !, Truth = true. marker_truth(Xs,Truth) :- Xs \= [_,1], !, Truth = false. marker_truth([_,1],true). marker_truth(Xs ,false) :- nonMarker__1(Xs). nonMarker__1(T) :- var(T), !, freeze(T,nonMarker__1(T)). nonMarker__1(T) :- T = [_|Arg], !, nonMarker__2(Arg). nonMarker__1(_). nonMarker__2(T) :- var(T), !, freeze(T,nonMarker__2(T)). nonMarker__2(T) :- T = [_|_], !, dif(T,[1]). nonMarker__2(_). 的新实现重新运行查询:

marker_truth/2

答案 2 :(得分:1)

您可以使用append/3之类的谓词。例如,要在其中第一次出现原子x时拆分列表,您会说:

?- L =  [a,b,c,d,x,e,f,g,x,h,i,j], once(append(Before, [x|After], L)).
L = [a, b, c, d, x, e, f, g, x|...],
Before = [a, b, c, d],
After = [e, f, g, x, h, i, j].

正如@false指出的那样,提出额外的要求可能会改变你的结果,但这是使用append/3的好处:

“拆分x上的列表,以便第二部分以h开头:

?- L =  [a,b,c,d,x,e,f,g,x,h,i,j], After = [h|_], append(Before, [x|After], L).
L = [a, b, c, d, x, e, f, g, x|...],
After = [h, i, j],
Before = [a, b, c, d, x, e, f, g].

这只是小费。