【问题标题】:Check if any element's frequency is above a limit检查任何元素的频率是否超过限制
【发布时间】:2016-02-20 17:10:51
【问题描述】:

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

【问题讨论】:

  • 你卡在哪里了?你有没有尝试过实现frequency/2?蛮力方法(效率不高,但可行)是递归遍历输入列表的每个元素,并检查其在原始列表中的频率(使用您的 count/3 谓词)与最大值。
  • 请更具体!什么是“频率”? ?- frequency([1,2,2,3,2,4],3). 应该成功吗? ?- frequency([1,2,2,3,2,2,2,4],3). 呢?
  • @luker count/3 给出特定数字的频率。我想取最大频率,它应该小于 4。如何得到它?
  • @repect 我的期望是任何大于 3 的频率都返回 false。?- frequency([1,2,2,3,2,2,2,4],3). 这里 2 的频率是 5。和 5>3。那么它将返回 false。

标签: list prolog prolog-dif


【解决方案1】:

使用

:- use_module(library(clpfd))。

如果我们基于辅助谓词list_counts/2,我们可以这样定义frequency/2

频率(Es,M):- list_counts(Es, Xss), maplist(arg(2), Xss, Zs), 地图列表(#>=(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).

【讨论】:

  • 是的。谢谢你的好答案。当然这是一个很好的解决方案。
【解决方案2】:

您可以首先尝试考虑可以解决此类问题的最“便宜”(在写作方面)的方式。我通常会尝试弄清楚如何使用标准命令行工具来做到这一点。例如,要在名为 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)

此时,您在Counts 中拥有Sorted 中每个元素的出现次数(诚然,比uniq --count 更冗长),您只需要检查其中是否有任何高于您的限制。做一些与上面 Prolog 中的awk 调用非常相似的事情:

maplist(=<(3), Counts)

免责声明:这只是解决问题的一种方法。我决定把它打出来,因为它表明如果你知道哪些工具已经可供你使用,你很少需要自己编写很多代码。

编辑

当然不用group_pairs_by_key/2;但是,了解它非常有用,这就是我链接实现的原因。对于这个问题,做一个稳定的排序就足够了,然后是一个简单地计算相同元素连续出现次数的谓词,并且只有在所有此类运行不超过限制时才会成功。执行此操作的谓词的基本结构与group_pairs_by_key/2 相同。

【讨论】:

  • s(X):我喜欢这种方法,但我们使用的是相同的工具……最终,这一切都归结为您喜欢使用的工具。
  • 我只有 SWI-Prolog(版本 7.1.17)。这有可能得到答案吗?
  • @Gamsh 这就是答案,你自己试过了吗?
  • @repeat 你可能听说过affordances 的概念。我试图在编程语言和工具的背景下找到关于该主题的好论文,以及它们如何影响程序员和他们可能考虑的解决方案,但都失败了。我确信一定有什么,我只是不知道到底要寻找什么。
  • @Gamsh 您的问题看起来很像家庭作业,guidelines 告诉您如何提问和回答这些问题。我试图遵循这些准则。如果这不是家庭作业,我深表歉意,但是,“给我密码”仍然不行。
【解决方案3】:

这段代码是怎么回事...

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

【讨论】:

  • 为什么要将空列表附加到某个东西:append([],[X1|T],L)?
  • 获取列表的第一个元素 X1 和其余的 T,因此附加一个空列表。
  • 为什么不[X1|T] = L?同样,为什么要附加单个元素而不是 [N1|N2] = Nappend/3 是一个有用的谓词,但统一和模式匹配更好。
  • @Giththan 没关系。在这种情况下,如果一旦找到数字2并计算频率。那么尾部也找到计数。我们如何消除这个?
  • @repeat。是的,我会考虑的。
猜你喜欢
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
  • 2021-01-13
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
  • 2022-12-01
  • 2011-12-24
相关资源
最近更新 更多