检查任何元素的频率是否超过限制

时间:2016-02-20 17:10:51

标签: list prolog prolog-dif

我想解决一个问题,即我有一个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).

3 个答案:

答案 0 :(得分:4)

使用

:- use_module(library(clpfd)).

如果我们建立辅助谓词list_counts/2,我们可以像这样定义frequency/2

frequency(Es, M) :-
   list_counts(Es, Xss),
   maplist(arg(2), Xss, Zs),
   maplist(#>=(M), Zs).

示例查询:

?- 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).

答案 1 :(得分:3)

你可以先考虑一下最便宜的" (在写作方面)你可以攻击这样的问题。我通常试图弄清楚如何使用标准命令行工具。例如,要在名为foo的文本文件中查找所有的出现次数,可以写一个(在Bash中):

sort foo | uniq --count

您可以阅读手册,但这里有一个示例:

$ 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) }'

(我相信也有更聪明的方法。)

使用上述文件,您将获得:

$ 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有什么帮助?好吧,一种简单的方法来模拟这样的管道:

foo | bar | baz # etc

是在Prolog中写一个像这样的连词:

foo(In, X0), bar(X0, X1), baz(X1, X2) % etc

回到你的问题:你可以使用msort/2(或者在你正在使用的实现中调用一个稳定的排序谓词)。然后,您需要计算相同元素的运行。在SWI-Prolog中,至少你有group_pairs_by_key/2。您可以使用它,例如如下(与同一个库中的其他谓词一起,您可以在同一链接中看到代码):

pairs_keys_values(Pairs, Sorted, Sorted),
group_pairs_by_key(Pairs, Grouped),
pairs_values(Grouped, Runs),
maplist(length, Runs, Counts)

此时,Sorted Counts中每个元素的出现次数(比uniq --count更加冗长),你只需要检查一下这些都超出了你的极限。要做一些非常类似于Prolog上面的awk调用的内容:

maplist(=<(3), Counts)

免责声明:这只是解决问题的一种方法。我决定输入它,因为它表明如果你知道已经有哪些工具可供你自己编写很多代码。

修改

当然没有必要使用group_pairs_by_key/2;但是,了解它非常有用,这就是我将实现联系起来的原因。对于这个问题,进行稳定排序就足够了,然后是一个简单计算同一元素连续出现次数的谓词,并且只有在所有这些运行都不长于限制时才会成功。执行该操作的谓词的基本结构与group_pairs_by_key/2相同。

答案 2 :(得分:1)

这段代码是什么......

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).