List 将列表元素的连续副本打包到子列表中
我需要一些帮助。我在数据库中搜索了一下,我对这个例子很感兴趣,但是答案对我没有帮助,所以我想发布我自己的问题 任务是将列表元素的连续副本打包到子列表中:List 将列表元素的连续副本打包到子列表中,list,prolog,dcg,List,Prolog,Dcg,我需要一些帮助。我在数据库中搜索了一下,我对这个例子很感兴趣,但是答案对我没有帮助,所以我想发布我自己的问题 任务是将列表元素的连续副本打包到子列表中: % ?- pack([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X). % X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]. 以下是我得到的: pack([], []). pack([X], [[X]]). pack(Liste, Ergebnis):- Liste = [H,
% ?- pack([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
% X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]].
以下是我得到的:
pack([], []).
pack([X], [[X]]).
pack(Liste, Ergebnis):-
Liste = [H, T|TS],
H \= T,
pack([T|TS], Ergebnis1),
append([[H]], Ergebnis1, Ergebnis).
pack([H, H|HS], Ergebnis):-
pack([H|HS], Ergebnis1),
append([H|HS], Ergebnis1, Ergebnis).
第一种情况非常有效(H\=T的情况)。第二个没有,我真的不知道为什么。有人能帮我解释一下这个问题吗
谢谢您的第四个子句试图将
[H | HS]
附加到结果中,这是不正确的,因为[H | HS]
是原始列表的尾部。你可以使它简单得多-
pack([H, H|HS], [[H|TFR]|TR]):-
pack([H|HS], [TFR|TR]).
本质上,它表示,当输入中的前两个条目相同时,第一个条目(即H
)需要被挂起到通过递归调用pack
规则生成的输出列表的第一个条目
请注意,第三个子句也可以简化,方法是将您立即“破解”的Liste
参数替换为子句标题中的“已破解”版本“inlined”,并对输出变量Ergebnis1
执行相同操作。最终版本应如下所示:
pack([H, T|TS], [[H]|TR]):-
H \= T,
pack([T|TS], TR).
前两个条款都是无关紧要的,看起来不错 第三条似乎合理。它说如果我打包
[H,T | TS]
和H\=T
,那么结果将是[H]
被打包的[T | TS]
结果的前面
第四条是问题:
pack([H, H|HS], Ergebnis):-
pack([H|HS], Ergebnis1),
append([H|HS], Ergebnis1, Ergebnis).
它表示打包[H,H | HS]
的结果与打包[H | HS]
然后在所有[H | HS]
前面加上前缀的结果相同。这似乎不合逻辑。当你打包[H | HS]
时,你会得到这样的东西:[[H,…,H]| X]
,现在你想把另一个H
放到第一个子列表的头部。因此,你应该:
pack([H, H|HS], Ergebnis):-
pack([H|HS], [HH|T]),
Ergebnis = [[H|HH]|T].
您可以使这些谓词更加紧凑:
pack([], []).
pack([X], [[X]]).
pack([H,T|TS], [[H]|PTS]):-
H \= T,
pack([T|TS], PTS).
pack([H, H|HS], [[H|HH]|T]):-
pack([H|HS], [HH|T]).
测试
| ?- pack([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]] ? a
no
| ?-
我将以稍微不同的方式处理问题,并将问题分解为两个更简单的任务 我们首先需要能够将列表划分为一个前缀,该前缀由列表开头的连续元素列表及其后缀(所有其他元素)组成: 一旦我们做到了这一点,剩下的就很简单了:
pack([],[]) . % packing an empty list yields the empty list
pack([X|Xs],[P,Ps]) :- % packing a non-empty list consists of
partition([X|Xs],P,T) , % - partitioning it into its prefix and suffix, and
pack(T,Ps) % - packing the suffix
. %
要避免附加,可以使用: 这个问题的答案中给出的所有其他实现在逻辑上都是不纯净的。它们不是单调的,因此当与非地面术语一起使用时,很容易在逻辑上变得不合理 这里建议的实现在逻辑上是纯的。它使用元谓词,它基于@false in提出的
if\u3
因此,让我们将splitlistIfAdj/3
与dif/3
结合使用,后者是dif/2
的具体化变体:
?- splitlistIfAdj(dif,[a,a,a,a,b,c,c,a,a,d,e,e,e,e],Lists).
Lists = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]. % succeeds deterministically
当我们保持单调时,
即使使用非基础术语,我们也能得到有意义的答案:
?- splitlistIfAdj(dif,[A,B,C],Lists).
A = B, B = C, Lists = [[C, C, C]] ;
A = B, dif(B,C), Lists = [[B, B], [C]] ;
dif(A,C), B = C, Lists = [[A], [C, C]] ;
dif(A,B), dif(B,C), Lists = [[A], [B], [C]].
我如何发布推荐信?通过发布链接。。。连续重复…:为什么
b
在[a、a、a、b、c、c、a、a、d、e、e、e、e、e]
中是连续重复的…?感谢您的帮助:)b不是连续重复的,它只是显示结果应该是什么样子的一个示例。但您的问题陈述在第二个参数中只讨论了连续重复。那么为什么b
在那里呢?嘿:谢谢你的帮助。你能向我解释一下你的意思吗?我并不“真正”理解这个程序的功能。TFR是指从静止到静止的尾巴吗?有时我在学习Prolog时会觉得很复杂。@user3637666[[H|TFR]| TR]
是一个列表。它的第一个条目也是一个列表。“内部列表”的第一个条目是H
,输入列表的标题(也等于输入列表的第二个条目);“内部列表”的尾部是TFR
,它是递归调用返回的头条目。外部列表的尾部是TR
,即从递归调用返回的输出列表的尾部。当您说Ergebnis=[[H | HH]| T]时,这是什么意思?我不知道这种语法形式。你是说头包含头和尾吗?@user3637666这意味着你有一个列表,它的头是一个列表,[H | HH]
,它的尾是T
。在Prolog中,您可以嵌入任意多个列表。所以[H | T]
是一个带有头H
和尾T
的列表。如果H
本身是一个列表(例如在列表列表中),那么H
要么是空的[]
,要么是一个由头和尾组成的列表本身。较短的版本也有一个很大的优势,即潜在的。我想知道它到底是如何编译的…@WillNess:目前使用上述代码实现的问题是索引。但除此之外,它们都使用常量空间“用于递归”。@johnjohn它可能适用于几个示例,但我要说的是,这是一个错误的实现,因为它将在其他有效情况下产生不正确的结果。仅仅为几个例子工作并不能使代码正确。我认为应该是pack([X | Xs],[P | Ps]):-…
。如果您使用dif/2
而不是(\=)/2
,那么您的代码将保持不变!
?- splitlistIfAdj(dif,[a,a,a,a,b,c,c,a,a,d,e,e,e,e],Lists).
Lists = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]. % succeeds deterministically
?- splitlistIfAdj(dif,[A,B,C],Lists).
A = B, B = C, Lists = [[C, C, C]] ;
A = B, dif(B,C), Lists = [[B, B], [C]] ;
dif(A,C), B = C, Lists = [[A], [C, C]] ;
dif(A,B), dif(B,C), Lists = [[A], [B], [C]].