List 检查是否有任何元素';s的频率高于一个极限

List 检查是否有任何元素';s的频率高于一个极限,list,prolog,prolog-dif,clpfd,List,Prolog,Prolog Dif,Clpfd,我想解决一个问题,我有一个Prolog元素列表。如果任何元素频率大于N,则返回false。我的期望如下 ?- frequency([1,2,2,2,5],3). true. ?- frequency([1,2,2,2,2,5],3). false. 我有一个获取特定元素频率的代码。对这个问题有什么想法吗 count(_, [], 0) :- !. count(X, [X|T], N) :- count(X, T, N2), N is N2 + 1. count(X, [Y|

我想解决一个问题,我有一个Prolog元素列表。如果任何元素频率大于
N
,则返回false。我的期望如下

?- frequency([1,2,2,2,5],3).
true.

?- frequency([1,2,2,2,2,5],3).
false.
我有一个获取特定元素频率的代码。对这个问题有什么想法吗

count(_, [], 0) :-
   !.
count(X, [X|T], N) :-
   count(X, T, N2),
   N is N2 + 1.
count(X, [Y|T], N) :-
   X \= Y,
   count(X, T, N).

您可以首先尝试思考解决此类问题的最“便宜”(就写作而言)的方法。我通常会想办法用标准的命令行工具来完成它。例如,要查找名为
foo
的文本文件中所有行的出现情况,可以编写(在Bash中):

您可以阅读手册,但以下是一个运行示例:

$ cat foo
a
b
b
b
c
d
d
a
b
d
c
$ sort foo | uniq --count
      2 a
      4 b
      2 c
      3 d
现在,一种询问“是否有任何一行的计数超过3?”的方法是使用
awk
如下:

sort foo | uniq --count | awk '{ if ($1 > 3) exit(1) }'
foo | bar | baz # etc
foo(In, X0), bar(X0, X1), baz(X1, X2) % etc
frequency(Es, M) :- list_counts(Es, Xss), maplist(arg(2), Xss, Zs), maplist(#>=(M), Zs). (我相信还有更聪明的方法。)

使用上述文件,您可以获得:

$ sort foo | uniq --count | awk '{ if ($1 > 3) exit(1) }'
$ echo $?
1
$ sort foo | uniq --count | awk '{ if ($1 > 4) exit(1) }'
$ echo $?
0
好的,那这对你学习Prolog有什么帮助呢?好的,一种模拟管道的简单方法如下:

sort foo | uniq --count | awk '{ if ($1 > 3) exit(1) }'
foo | bar | baz # etc
foo(In, X0), bar(X0, X1), baz(X1, X2) % etc
frequency(Es, M) :- list_counts(Es, Xss), maplist(arg(2), Xss, Zs), maplist(#>=(M), Zs). 在序言中写一个连词,如下所示:

sort foo | uniq --count | awk '{ if ($1 > 3) exit(1) }'
foo | bar | baz # etc
foo(In, X0), bar(X0, X1), baz(X1, X2) % etc
frequency(Es, M) :- list_counts(Es, Xss), maplist(arg(2), Xss, Zs), maplist(#>=(M), Zs). 回到您的问题:您可以使用
msort/2
(或者在您使用的实现中调用稳定排序谓词)。然后,您需要计算相同元素的运行次数。在SWI Prolog中,至少您有。例如,您可以使用它,如下所示(与同一库中的其他谓词一起,您可以在同一链接中看到代码):

在这一点上,您已经对
中每个元素的出现次数进行了排序
Counts
(无可否认,这比
uniq--count
更详细),您只需检查其中是否有任何元素超出了您的限制。要执行与上面在Prolog中的
awk
调用非常类似的操作:

maplist(=<(3), Counts)

maplist(这段代码是怎么回事

frequency(L,N):-getall(L,L1), max_member(A,L1),A=<N.

getall([],[]).
getall(L,N):-append([],[X1|T],L),count(X1,L,N1),getall(T,N2),append([N1],N2,N).
频率(L,N):-getall(L,L1),max_成员(A,L1),A=使用

示例查询:

?- frequency([1,2,2,2,5], 3).
true.

?- frequency([1,2,2,2,2,5], 3).
false.
多亏了这一点,我们可以提出相当一般的问题,也可以得到逻辑上合理的答案

?- frequency([A,B,C], 2).
       A=B ,           dif(B,C)
;                A=C , dif(B,C)
;            dif(A,C),     B=C
;  dif(A,B), dif(A,C), dif(B,C).

你被困在哪里了?你有没有尝试过实现
frequency/2
?蛮力方法(效率不高,但会奏效)是递归地遍历输入列表的每个元素,并对照最大值检查它在原始列表中的频率(使用
count/3
谓词)。请更具体一些!什么是“频率”?应该
?-频率([1,2,2,3,2,4],3)。
成功了?那么
呢?-频率([1,2,2,3,2,2,4],3).
@luker
count/3
给出一个特定数字的频率。我想取最大频率,它应该小于4。如何获得它?@repect我的期望是任何大于3的频率返回false。
?-频率([1,2,2,3,2,2,2,4],3)。
这里2的频率是5。而5>3。然后它将返回false.s(X):我喜欢这种方法,但我们使用的是相同的工具…最后,这一切都取决于您使用的工具。我只有SWI Prolog(版本7.1.17)“这是答案吗?”GAMSH,这是答案,你自己试过了吗?“重复你可能已经听说过这个概念。在编程语言和工具的背景下,我尝试并没有找到关于该主题的好论文,也不知道它们如何影响程序员和他们可能考虑的解决方案。我相信必须有。有点什么,我只是不知道到底要找什么。@Gamsh你的问题看起来很像家庭作业,关于如何提问和回答这些问题有很多建议。我试着遵循这些指导原则。如果这不是家庭作业,我很抱歉,但是,“给我代码”仍然不好。为什么要在某个东西后面附加一个空列表:
append([],[X1 | t],L)
?取列表中的第一个元素
X1
和其余的
T
,因此附加一个空列表。为什么不
[X1 | T]=L
?同样,为什么不附加一个元素而不是
[N1 | N2]= N< /代码>?<代码>附件/ 3 < /代码>是一个有用的谓词,但是“统一”和“模式匹配”甚至更好些。“Giththan是可以的。在这种情况下,一旦找到了数字<代码> 2 /代码>并计数频率。那么尾部分也会找到。我们如何才能消除这个问题?”重复。是的,我会考虑。谢谢。很好的回答。当然是。一个很好的解决方案。