我有一个列表,例如[(1,2),(3,4),(5,2),(4,2),(8,0)],我想删除,例如,所有不是(_,2)的元素。所以在这种情况下,我最终会得到一个这样的列表:[(1,2),(5,2),(4,2)]。 我在努力:
conta_pos(NL, _, NL):-
Idk what to do here, !.
conta_pos([(L,C)|T], C, _):-
conta_pos_aux([()], C, _).
conta_pos([(_,C)|T], _, _):-
conta_pos(T, _, _).
第一个参数表示初始列表,第二个参数表示我希望列表保留的元素,第三个参数表示我的新列表。
请记住,我对Prolog很新。
(我想要做的实际情况是计算初始中的元素数量,在本例中为(_,2),这样就可以了3.我想的是然后使用length \ 2来计算它们,但如果你有更好的建议,我会全力以赴!如果你想知道我要做的是什么,请随时问一下)
答案 0 :(得分:3)
您正在描述列表,因此您可以将DCG用于任务,因为它们通常会产生易于阅读的代码。此外,您可以使用其他参数来计算列表中的元素,因为它们正在被遍历。请考虑以下代码:
list_filtered_length(L,F,Len) :- % the filtered list F is described
phrase(filtered_len(L,Len,0),F). % by the DCG filtered_len//3
filtered_len([],N,N) --> % if the list is empty, the counter is the length
[]. % and the filtered list is empty
filtered_len([(A,2)|Ps],N,C0) --> % if the head of the list is (A,2)
{C1 is C0+1}, % the counter is increased
[(A,2)], % (A,2) is in the filtered list
filtered_len(Ps,N,C1). % the same for the tail
filtered_len([(_,B)|Ps],N,C) --> % if the head of the list is (_,B)
{dif(B,2)}, % with B not being 2, it's not in the list
filtered_len(Ps,N,C). % the same for the tail
使用您的示例查询此谓词会产生所需的结果:
?- list_filtered_length([(1,2),(3,4),(5,2),(4,2),(8,0)],F,Len).
F = [ (1, 2), (5, 2), (4, 2)],
Len = 3 ;
false.
显然,如果要应用不同的过滤器,则必须重写两个递归DCG规则。将过滤器定义为单独的谓词并将其作为参数传递会更好,从而使谓词更具通用性。如果只有一个解决方案,确定性地使谓词成功也是很好的。这可以通过if_/3和(=)/3来实现。为了用作if_/3
的第一个参数,过滤谓词需要将其真值作为附加参数:
filter_t((_,X),T) :-
if_(X=2,T=true,T=false).
如您所见,如果过滤条件成立,则最后一个参数为true
,否则为false
:
?- filter_t((1,1),T).
T = false.
?- filter_t((1,2),T).
T = true.
现在可以使用过滤器的附加参数重新定义谓词,如下所示:
list_filtered_by_length(L,LF,F_2,Len) :- % F_2 is the filter argument
phrase(filtered_by_len(L,F_2,Len,0),LF).
filtered_by_len([],_F_2,N,N) -->
[].
filtered_by_len([P|Ps],F_2,N,C0) -->
{if_(call(F_2,P),(X=[P], C1 is C0+1),
(X=[], C1 = C0))},
X, % X is in the filtered list
filtered_by_len(Ps,F_2,N,C1).
如果列表的头部符合过滤条件(call(F_2,P)
),则它位于过滤后的列表(X=[P]
)中,并且计数器增加(C1 is C0+1
),否则它是不在列表中(X=[]
)且计数器未增加(C1 = C0
)。
现在,示例查询确定性地成功:
?- list_filtered_by_length([(1,2),(3,4),(5,2),(4,2),(8,0)],F,filter_t,Len).
F = [ (1, 2), (5, 2), (4, 2)],
Len = 3.
如果要过滤其他内容,只需定义不同的过滤谓词即可。例如,如果要从对列表中过滤所有相等元素对,则可以定义...
filter2_t(X-Y,T) :-
if_(X=Y,T=true,T=false).
...然后查询:
?- list_filtered_by_length([a-a,b-c,d-d,e-f],F,filter2_t,Len).
F = [a-a, d-d],
Len = 2.
修改强>
或者,您可以使用tfilter/3非常紧凑地表达这种关系,如评论中的@false所示。与DCG版本一样,您将一个reifying过滤器谓词作为第三个参数传递,然后将其用作tfilter/3
的第一个参数。随后,内置的length/2
。
list_filtered_by_length(L,FL,F_2,Len) :-
tfilter(F_2,L,FL),
length(FL,Len).
以上查询产生与DCG版本相同的答案。