【问题标题】:Split a list in separate lists将列表拆分为单独的列表
【发布时间】:2015-05-25 22:26:31
【问题描述】:

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

我想拆分我的列表是单独的列表。

例子:

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] 的术语之间的列表。

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

约尔格

【问题讨论】:

    标签: prolog


    【解决方案1】:

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

    以下内容基于if_/3splitlistIf/3 和具体化谓词marker_truth/2marker_truth(M,T)M 的“标记”特性具体化为真值Ttruefalse)。

    is_marker([_,1])。 % 未具体化 marker_truth([_,1],true)。 %具体化:变体#1 marker_truth(Xs,false) :- 差异(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]]]? ; % 好的 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]) ? ; % 坏的 %% 查询中止(省略了其他 6 个错误答案)

    天哪!

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

    猜猜是谁的错! marker_truth/2的第二个子句:

    marker_truth(Xs,false) :- dif(Xs,[_,1])。 % 坏的

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

    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]]]? ; 不

    有效!然而,在考虑所需的编码工作时,很明显,无论是代码生成方案还是 必须设计dif/2 的变体(显示上述行为)。


    编辑 2015-05-25

    以上实现marker_truth/2有点工作,但还有很多不足之处。考虑:

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

    这个答案不是我们想要得到的。要了解为什么不这样做,让我们看看integer_truth/2 的类似用法的答案:

    ?- 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 的新实现重新运行上面的查询:

    ?- marker_truth(M,Truth).                   % most general use
    Truth = true,  M = [_A,1] ;
    Truth = false, freeze(M, nonMarker__1(M)).
    

    【讨论】:

    • 为什么不进行查询以检测不正确的答案替换,而不是显示答案替换墙呢?这将减少突出显示的需要。
    • 在“OMG”之后:你为什么不给出具体的问题,为什么你对第一个版本不满意?我认为没有你就不容易。
    【解决方案2】:

    不清楚您所说的“一组列表”是什么意思。在您的示例中,您从[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,[_])

    【讨论】:

    • 非常感谢您的回答......它以这样的标记开始并以这样的标记结束......并且谓词是[]。我会尽力理解你的答案。非常感谢
    【解决方案3】:

    您可以使用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].
    

    这只是提示。

    【讨论】:

    • 缺点:这种方法并不坚定。如果(部分)给出BeforeAfter ,则结果可能是不同的。
    • .. 喜欢After = [h|_]
    • @false 是的,但这是怎么回事?说After 必须以某些东西开头(在您的示例中,After = [h|_],只是提出了另一个要求,并且解决方案是“正确的”,例如,您得到了您所要求的。
    • 问题在于After = [h|_], g(After)g(After), After = [h|_] 的含义完全不同。因此,您必须考虑执行的所有细节,而不仅仅是一组基本解决方案。更复杂意味着更少的机会做对。
    • @fase 是的,因为once/1。如果它不存在,它会按预期工作。
    猜你喜欢
    • 1970-01-01
    • 2020-12-14
    • 2018-05-17
    • 2017-11-02
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 2021-07-24
    • 2016-11-04
    相关资源
    最近更新 更多