【问题标题】:Prolog: Function that returns the most frequent element in a listProlog:返回列表中出现频率最高的元素的函数
【发布时间】:2018-05-21 16:49:07
【问题描述】:

我有一个任务需要一个函数,该函数返回(如果存在)一个显示在列表一半以上的元素,否则它返回 no。所以我做了一个函数来查找列表的长度,但现在我需要一个方法来

查找最递归的元素以及在列表中找到它的次数

有什么想法吗?我是 Prolog 的新手,为了我的任务而要求我,所以如果有人要帮助我,只是给我提示或启发我,我不希望任何实际的代码复制粘贴。

【问题讨论】:

  • 它可能与this 重复。
  • 如果它需要一个函数,那么你就不走运了。 Prolog 语言没有函数。您可以查看99 Prolog Problems,它有简单的问题和答案,尤其是列表处理问题。这将向您展示如何编写一个递归处理列表的谓词。
  • 我们能不能不要因为说“功能”而在 cmets 中殴打人们?是的,在答案中指出正确的术语是个好主意,但是除了对某个词的抱怨之外别无其他的尖刻评论对任何人都没有用。
  • @IsabelleNewbie 此外,函数是关系的一个特例。

标签: list prolog


【解决方案1】:

图书馆(aggregate) 值得学习...

?- L=[1,2,3,3,3,1,2,3],aggregate(max(C,E),aggregate(count,member(E,L),C),R).
L = [1, 2, 3, 3, 3, 1, 2, 3],
R = max(4, 3).

编辑:考虑到出现wrt列表长度的要求:

?- L=[3,2,6,2,4],length(L,Len),HalfLen is Len/2, aggregate(max(C,E),(aggregate(count,member(E,L),C),C>HalfLen),R).
false.

【讨论】:

    【解决方案2】:

    foldl 可能是你的朋友:

    :- use_module(library(lambda)).
    count_repeat(L, R, N) :-
        foldl(\X^Y^Z^(select(V-X, Y, Y1)-> V1 is V+1, Z = [V1-X|Y1]; Z = [1-X|Y]), L, [], L1),
        sort(L1,L2),
        last(L2, N-R).
    

    结果:

    ?- count_repeat([3,2,6,2,4,1,4,2,5,3,2,4,1,2,3,1,2,4,5,3,2] , R, N)。

    R = 2,

    N = 7。

    【讨论】:

    • 考虑L=[3,2,6,2,4]
    • @Will Ness>> 我得到 R=N, N = 2,问题出在哪里?
    • 在这种情况下,OP 希望得到“不”。
    【解决方案3】:

    有一种方法(嗯,无限的方法)可以使用 prolog 内置函数来解决这个问题,例如 sort/2findall/3member/2include/3length/2

    ?- List=[3,2,6,2,2,1,4,2,2,2,2,4,1,2,3,2,2,4,2,3,2],
        sort(List, Uniq),                 % sort removing duplicate elements
        findall([Freq, X], (
            member(X, Uniq),              % for each unique element X
            include(=(X), List, XX),      %
            length(XX, Freq)              % count how many times appears in List
        ), Freqs),
        sort(Freqs, SFreqs),              % sort (by frequency)
        last(SFreqs, [Freq, MostCommon]), % last pair is the most common
        length(List, ListLen),
        Freq > ListLen/2.                 % is frequency greater than half list length?
    

    列表 = [3, 2, 6, 2, 2, 1, 4, 2, 2|...],

    Uniq = [1, 2, 3, 4, 6],

    频率 = [[2, 1], [12, 2], [3, 3], [3, 4], [1, 6]],

    SFreqs = [[1, 6], [2, 1], [3, 3], [3, 4], [12, 2]],

    频率 = 12,

    最常见 = 2,

    列表长度 = 21。

    根据讲师为解决练习设置的限制,您可能需要自己实现这些内置函数中的一个或多个。

    另一种更有效的方法是使用msort/2,然后创建排序列表的运行长度编码,然后再次排序,并选择代表最常出现的元素的元素。现在我无法弄清楚如何在不定义辅助递归谓词的情况下进行行程编码,所以这里是:

    count_repeated([Elem|Xs], Elem, Count, Ys) :-
        count_repeated(Xs, Elem, Count1, Ys), Count is Count1+1.
    count_repeated([AnotherElem|Ys], Elem, 0, [AnotherElem|Ys]) :-
        Elem \= AnotherElem.
    count_repeated([], _, 0, []).
    
    rle([X|Xs], [[C,X]|Ys]) :-
        count_repeated([X|Xs], X, C, Zs),
        rle(Zs, Ys).
    rle([], []).
    

    那么,可以通过以下方式获取最常见的元素:

    ?- List=[3,2,6,2,2,1,4,2,2,2,2,4,1,2,3,2,2,4,2,3,2],
        msort(List, SList),
        rle(SList, RLE),
        sort(RLE, SRLE),
        last(SRLE, [Freq, MostCommon]),
        length(List, ListLen),
        Freq > ListLen/2.
    

    列表 = [3, 2, 6, 2, 2, 1, 4, 2, 2|...],

    SList = [1, 1, 2, 2, 2, 2, 2, 2, 2|...],

    RLE = [[2, 1], [12, 2], [3, 3], [3, 4], [1, 6]],

    SRLE = [[1, 6], [2, 1], [3, 3], [3, 4], [12, 2]],

    频率 = 12,

    最常见 = 2,

    列表长度 = 21。

    【讨论】:

    • 因为你有所有元素的频率,你可以选择最频繁的元素 - 没有排序, - 然后总结所有其余元素的频率,并比较计数。这甚至可以在 one 遍历中完成。 :)
    猜你喜欢
    • 2019-08-15
    • 2015-07-01
    • 2022-01-11
    • 1970-01-01
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    相关资源
    最近更新 更多