我正在尝试编写prolog代码,删除列表列表中所有列表中的所有标点符号(。,!?etc)。这就是我到目前为止所做的:
delete_punctuation(_,[],_).
delete_punctuation(Character,[List|Tail],Resultlist) :-
delete(List,Character,NewList),
delete_punctuation(Character,Tail,[NewList|Resultlist]).
而'人物'将是33!或46。因为我将仅在字符代码列表上使用它。 (我知道,该函数实际上也适用于我想从列表中删除的其他元素。)
我在询问时收到的结果:
delete_punctuation(33,[[45,33,6],[4,55,33]],X).
只是
|: true.
但是,我希望它是:
|: X = [[45,6],[4,55]].
我需要改进什么?
答案 0 :(得分:1)
对于这个问题,我通过分别解决两个子问题解决它,即:
为此,我这样做:
exclude2(_, [], []).
exclude2(Code, [Code|Xs], Ys) :-
!, % ignore the next clause if codes match
exclude2(Code, Xs, Ys).
exclude2(Code, [X|Xs], [X|Ys]) :-
% else, Code != X here
exclude2(Code, Xs, Ys).
请注意某些实现,例如SWI-Prolog provide exclude/3
as a built-in,因此您实际上不需要自己定义它。
现在,将上述谓词应用于列表列表:
delete_punctuation(_, [], []).
delete_punctuation(Code, [L|Ls], [NewL|NewLs]) :-
exclude(Code, L, NewL),
delete_punctuation(Code, Ls, NewLs).
然而,同样,根据实现,可以使用内置的maplist/3
来实现相同的效果,而无需定义新的谓词:
?- maplist(exclude2(33), [[45,33,6],[4,55,33]], X).
X = [[45, 6], [4, 55]] ;
false.
n.b。如果您想使用所有SWI内置插件,exclude/3
需要将测试作为目标,如下所示:
?- maplist(exclude(==(33)), [[45,33,6],[4,55,33]], X).
X = [[45, 6], [4, 55]] ;
false.
对于更通用的方法,您甚至可以将要排除的所有代码(例如任何和所有标点字符代码)添加到列表中以用作过滤器:
excludeAll(_, [], []).
excludeAll(Codes, [Code|Xs], Ys) :-
member(Code, Codes),
!,
excludeAll(Codes, Xs, Ys).
excludeAll(Codes, [X|Xs], [X|Ys]) :-
excludeAll(Codes, Xs, Ys).
然后您可以添加包含要删除的所有代码的列表:
?- maplist(excludeAll([33,63]), [[45,33,6],[4,55,33,63]], X).
X = [[45, 6], [4, 55]] ;
false.