我想计算列表中元素的出现次数
I want to count the occurrences of an element in a list
我想计算列表中某个元素的出现次数,如果有,则谓词 unique 为真,否则为假。但是,如果该元素出现不止一次,Prolog 会认为它为真。我不知道该怎么办...
count([], X, 0).
count([X|T], X, Y) :- count(T, X, Z), Y is 1+Z, write(Z).
count([_|T], X, Z) :- count(T, X, Z).
unique(St, [Y|RestList]) :- count([Y|RestList], St, N), N =:= 1.
使用你自己的子句,我只是稍微优化了程序:
- 用匿名变量替换单例变量
- 在计数谓词的第二个子句上添加一个截断
- 删除唯一子句的第二个条件。
这是现在的节目:
count([],_,0).
count([X|T],X,Y):- !, count(T,X,Z), Y is 1+Z.
count([_|T],X,Z):- count(T,X,Z).
unique(St,L):- count(L,St,1).
咨询:
?- count([2,3,4,3], 3,N).
N = 2.
?- unique(3, [2,3,4,5]).
true.
只要第一个参数是基础列表,该解决方案就有效。在其他一些情况下,它是不正确的:
?- count([E], a, 0).
false.
这里请教
How must the element E
of a list of length 1 look like such that the list contains 0 occurences of a
?
事实上有答案,比如 E = b
或 E = c
:
?- count([b],a,0).
true.
?- count([c],a,0).
true.
出于这个原因,Prolog 的回答是不完整。它应该说,是的。但是怎么办?
count([], _, 0).
count([E|Es], F, N0) :-
count(Es, F, N1),
if_(E = F, D = 1, D = 0),
N0 is N1+D.
这使用了if_/3
and (=)/3
.
?- length(Xs, I), count_dif(Xs, a, N).
Xs = [],
I = N, N = 0
; Xs = [a],
I = N, N = 1
; Xs = [_A],
I = 1,
N = 0,
dif(_A, a)
; Xs = [a, a],
I = N, N = 2
; Xs = [_A, a],
I = 2,
N = 1,
dif(_A, a) ;
Xs = [a, _A],
I = 2,
N = 1,
dif(_A, a) ;
Xs = [_A, _B],
I = 2,
N = 0,
dif(_A, a),
dif(_B, a)
...
为了进一步改进这一点,我们可能会使用 library(clpfd)
,因为它在 SICStus、YAP 和 SWI 中可用。
:- use_module(library(clpfd)).
count([], _, 0).
count([E|Es], F, N0) :-
N0 #>= 0,
if_(E = F, D = 1, D = 0),
N0 #= N1+D,
count(Es, F, N1).
现在甚至以下终止:
?- count([a,a|_], a, 1).
false.
?- N #< 2, count([a,a|_], a, N).
false.
我想计算列表中某个元素的出现次数,如果有,则谓词 unique 为真,否则为假。但是,如果该元素出现不止一次,Prolog 会认为它为真。我不知道该怎么办...
count([], X, 0).
count([X|T], X, Y) :- count(T, X, Z), Y is 1+Z, write(Z).
count([_|T], X, Z) :- count(T, X, Z).
unique(St, [Y|RestList]) :- count([Y|RestList], St, N), N =:= 1.
使用你自己的子句,我只是稍微优化了程序:
- 用匿名变量替换单例变量
- 在计数谓词的第二个子句上添加一个截断
- 删除唯一子句的第二个条件。
这是现在的节目:
count([],_,0).
count([X|T],X,Y):- !, count(T,X,Z), Y is 1+Z.
count([_|T],X,Z):- count(T,X,Z).
unique(St,L):- count(L,St,1).
咨询:
?- count([2,3,4,3], 3,N).
N = 2.
?- unique(3, [2,3,4,5]).
true.
只要第一个参数是基础列表,该解决方案就有效。在其他一些情况下,它是不正确的:
?- count([E], a, 0).
false.
这里请教
How must the element
E
of a list of length 1 look like such that the list contains 0 occurences ofa
?
事实上有答案,比如 E = b
或 E = c
:
?- count([b],a,0).
true.
?- count([c],a,0).
true.
出于这个原因,Prolog 的回答是不完整。它应该说,是的。但是怎么办?
count([], _, 0).
count([E|Es], F, N0) :-
count(Es, F, N1),
if_(E = F, D = 1, D = 0),
N0 is N1+D.
这使用了if_/3
and (=)/3
.
?- length(Xs, I), count_dif(Xs, a, N).
Xs = [],
I = N, N = 0
; Xs = [a],
I = N, N = 1
; Xs = [_A],
I = 1,
N = 0,
dif(_A, a)
; Xs = [a, a],
I = N, N = 2
; Xs = [_A, a],
I = 2,
N = 1,
dif(_A, a) ;
Xs = [a, _A],
I = 2,
N = 1,
dif(_A, a) ;
Xs = [_A, _B],
I = 2,
N = 0,
dif(_A, a),
dif(_B, a)
...
为了进一步改进这一点,我们可能会使用 library(clpfd)
,因为它在 SICStus、YAP 和 SWI 中可用。
:- use_module(library(clpfd)).
count([], _, 0).
count([E|Es], F, N0) :-
N0 #>= 0,
if_(E = F, D = 1, D = 0),
N0 #= N1+D,
count(Es, F, N1).
现在甚至以下终止:
?- count([a,a|_], a, 1).
false.
?- N #< 2, count([a,a|_], a, N).
false.