将列表拆分为单独的列表
Split a list in separate lists
我必须为我的列表定义更多限制条件。
我想拆分我的列表是单独的列表。
示例:
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] 之间的一组列表。
如果你能给我小费就太好了。不想解决,只提示如何解决。
约尔格
您可以使用像 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].
这只是小费。
不清楚你所说的 "group of lists" 是什么意思。在您的示例中,您从符合 [_,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,[_])
此实现尝试保留 logical-purity 而不将列表项限制为 [_,_]
,例如
确实如此。
我可以看到施加上述限制 确实 很有意义......我仍然想解除它---并解决更普遍的问题。
以下是基于if_/3
, splitlistIf/3
和具体化谓词marker_truth/2
。
marker_truth(M,T)
将 M
的 "marker" 性具体化为真值 T
(true
或 false
)。
is_marker([_,1]). % non-reified
marker_truth([_,1],true). % reified: variant #1
marker_truth(Xs,false) :-
dif(Xs,[_,1]).
很简单!让我们在查询中一起尝试 splitlistIf/3
和 marker_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)
哦!
上面显示的第二个答案肯定不是我们想要的。
显然,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
有效!然而,在考虑所需的编码工作时,很明显代码生成方案或
必须设计 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)).
我必须为我的列表定义更多限制条件。
我想拆分我的列表是单独的列表。
示例:
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] 之间的一组列表。
如果你能给我小费就太好了。不想解决,只提示如何解决。
约尔格
您可以使用像 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].
这只是小费。
不清楚你所说的 "group of lists" 是什么意思。在您的示例中,您从符合 [_,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,[_])
此实现尝试保留 logical-purity 而不将列表项限制为 [_,_]
,例如
以下是基于if_/3
, splitlistIf/3
和具体化谓词marker_truth/2
。
marker_truth(M,T)
将 M
的 "marker" 性具体化为真值 T
(true
或 false
)。
is_marker([_,1]). % non-reified marker_truth([_,1],true). % reified: variant #1 marker_truth(Xs,false) :- dif(Xs,[_,1]).
很简单!让我们在查询中一起尝试 splitlistIf/3
和 marker_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)
哦!
上面显示的第二个答案肯定不是我们想要的。
显然,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
有效!然而,在考虑所需的编码工作时,很明显代码生成方案或
必须设计 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)).