【问题标题】:Which list item is the most common哪个列表项最常见
【发布时间】:2010-11-28 00:29:49
【问题描述】:

我正在尝试查找最常见的列表项 common([b,a,a,a,c,d,b,f,s,f,s,f,s,f,s,f,f ],R) 所以结果应该是 R=f, 我在想如果我们拿列表,到列表末尾取 el=b ,num1=1 然后回到开头并比较 if b=b ,num1=num1+1 else a!=b then if num2 =num2+1 , num1>num2 recursion else el=a 或类似的东西,但我在将其转换为 Prolog 时遇到了一些困难。

insert_sort 对列表进行排序,但出于一些有趣的原因,如果我使用 las(X,Y)(我会覆盖原来的 last/2),如果我使用 last(X,Y),我会得到 4-a,我只会得到一个...

most_common([X|Y],J):-
    insert_sort([X|Y],[R|Rs]),             
    count_runs([R|Rs],G),
    las(G,J).

las([N-Y],Y).
las([_|T],Y):- las(T,Y).
las([_|Tail], Y) :- las(Tail, Y).

insert_sort(List,Sorted):-
   i_sort(List,[],Sorted).

i_sort([],Acc,Acc).
i_sort([H|T],Acc,Sorted):- 
    insert(H,Acc,NAcc),
    i_sort(T,NAcc,Sorted).

insert(X,[],[X]).     
insert(X,[Y|T],[Y|NT]):- X @> Y, insert(X,T,NT).
insert(X,[Y|T],[X,Y|T]):- X @=< Y.

【问题讨论】:

    标签: prolog


    【解决方案1】:

    这看起来像家庭作业,所以我不会给你一个完整的答案,但会建议你如何以一种特定的方式解决它,这不一定是最好的方式:

    • 将列表排序为排序顺序(如果这足够好,则按术语的标准顺序):查看sort/2 例程。例如,[b,a,a,a,c,d,b] 变为 [a,a,a,b,b,c,d]

    • 获取排序列表并计算“运行”的大小,可能会将[a,a,a,b,b,c,d] 转换为[3-a,2-b,1-c,1-d](其中-/2 只是另一个术语)。例如,考虑以下代码:


    count_runs([E|Es], C) :-
          % defer to count_runs/3 with an initial count of element E
        count_runs(Es, 1-E, C).
    
      % return the final count for Y elements if none remain (base case)
    count_runs([], N-Y, [N-Y]). 
    
    count_runs([X|Es], N-Y, [N-Y|Rest]) :-
          % if X is not equal to Y, record the count and continue next run
        X \== Y, !,  
        count_runs([X|Es], Rest).
    
    count_runs([_X|Es], N-Y, Rest) :-
          % else X equals Y; increment the counter and continue
        NPlusOne is N + 1,
        count_runs(Es, NPlusOne-Y, Rest).
    

    • 执行类似keysort/2 的操作,以根据它们的键值(即计数的数字,将[3-a,2-b,1-c,1-d] 转换为[1-c,1-d,2-b,3-a])对术语进行排序。然后,列表中出现次数最多的元素是列表末尾具有相同键值的值(即,这里是最后一个术语3-a中的a)。一般来说,它们可能不止一个出现最多的元素(与另一个相同)。

    祝你好运。

    【讨论】:

    • most_common([a,a,b,f,f,d,f,s,d,s,d,s,d,s],E)。 E = f .
    • 这是完整代码的部分:most_common([X|Y],C):- count_runs([X|Y],K),last(K,C)。 %所以我们已经对列表 K 进行了排序,并使用 Last() 找到了字母 last([N-Y], Y)。最后([_|尾巴],Y):-最后(尾巴,Y)。但是假设我们有一个这样的列表: most_common([a,a,b,f,f,d,f,s,d,s,d,s,d,s],E)。 -> last([1-b, 1-f, 1-s, 1-f, 1-s, 1-f, 1-s, ... - ...|...], a) 和最常见的项目是 a 但不是 f 所以我们有一个小问题:D
    • 对整体问题的一个小优化是定义count_runs/2,这样它会以相反的顺序累积项目计数,将它们按从最大到最小的计数排序,从而产生出现次数最多的元素@987654336 @ 在结果列表的头部,即[_-E|_]
    【解决方案2】:

    基于Prolog lambdas,我们使用元谓词tcount/3reduce/3,以及具体化的术语相等谓词(=)/3

    :- use_module(library(lambda)).
    
    mostcommon_in(E,Xs) :-
       tcount(=(E),Xs,M),
       maplist(Xs+\X^N^(tcount(=(X),Xs,N)),Xs,Counts),
       reduce(\C0^C1^C^(C is max(C0,C1)),Counts,M).
    

    示例查询:

    ?- mostcommon_in(X,[a,b,c,d,a,b,c,a,b])。 X = 一个; X = 乙; 错误的。

    请注意,这是单调(与早期的快速破解版本不同)。看!

    ?- mostcommon_in(X,[A,B,C,D,A,B,C,A,B]), A=a,B=b,C=c,D=d。 X = a, A = a, B = b, C = c, D = d ; X = b, A = a, B = b, C = c, D = d ; 错误的。

    【讨论】:

      【解决方案3】:

      保留 by 使用list_counts/2 定义mostcommonitem_in/2 如下:

      mostcommonitem_in(E,Xs) :-
         list_counts(Xs,Cs),                      % tag items with multiplicity
         maplist(\ (X-N)^(M-X)^(M is -N),Cs,Ps),  % prepare keysorting
         keysort(Ps,[Max-_|_]),                   % sort ascending by negated count
         member(Max-E,Ps).                        % pick most common ones
      

      让我们运行一个查询!

      ?- mostcommonitem_in(X,[a,b,c,d,a,b,c,a,b]).
      X = a ;
      X = b ;
      false.                                % OK
      

      但是,还是单调吗?

      ?- mostcommonitem_in(X,[A,B,C,D,A,B,C,A,B]), A=a,B=b,C=c,D=d.
      X = A, A = a, B = b, C = c, D = d ;
      X = B, B = b, A = a, C = c, D = d ;
      false.                                % OK: monotone
      

      有速度吗? (与我在my previous answer to this question 中显示的纯答案相比)

      % 老的 ?- 长度(Xs,5), 时间(findall(t,mostcommon_in(E,Xs),Ts)), 长度(Ts,N_sols)。 % 854,636 次推理,0.115 个 CPU,0.115 秒(100% CPU,7447635 个嘴唇) N_sols = 71,Xs = [_,_,_,_,_],Ts = [t,t,t|...]。 ?- 长度(Xs,6), 时间(findall(t,mostcommon_in(E,Xs),Ts)), 长度(Ts,N_sols)。 % 4,407,975 次推理,0.449 CPU,0.449 秒(100% CPU,9813808 唇) N_sols = 293,Xs = [_,_,_,_,_,_],Ts = [t,t,t|...]。 ?- 长度(Xs,7), 时间(findall(t,mostcommon_in(E,Xs),Ts)), 长度(Ts,N_sols)。 % 24,240,240 次推理,2.385 个 CPU,2.384 秒(100% CPU,10162591 个嘴唇) N_sols = 1268,Xs = [_,_,_,_,_,_,_],Ts = [t,t,t|...]。 % 新的 ?- 长度(Xs,5), 时间(findall(t,mostcommonitem_in(E,Xs),Ts)), 长度(Ts,N_sols)。 % 4,031 推理,0.001 CPU 在 0.002 秒(93% CPU,2785423 唇) N_sols = 71,Xs = [_,_,_,_,_],Ts = [t,t,t|...]。 ?- 长度(Xs,6), 时间(findall(t,mostcommonitem_in(E,Xs),Ts)), 长度(Ts,N_sols)。 % 17,632 推理,0.002 CPU 在 0.002 秒(100% CPU,9194323 唇) N_sols = 293,Xs = [_,_,_,_,_,_],Ts = [t,t,t|...]。 ?- 长度(Xs,7), 时间(findall(t,mostcommonitem_in(E,Xs),Ts)), 长度(Ts,N_sols)。 % 82,263 推理,0.023 CPU 在 0.023 秒(100% CPU,3540609 唇) N_sols = 1268,Xs = [_,_,_,_,_,_,_],Ts = [t,t,t|...]。

      【讨论】:

      • counts_flipped/2: 哦,这些手册 maplist 和 λ 编译器。
      【解决方案4】:

      我可以给你一个高层次的答案:你可以对列表进行排序,然后相对容易地逐个计数项目,并更新迄今为止最常见的项目。

      【讨论】:

        猜你喜欢
        • 2013-09-20
        • 2015-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-01
        • 2015-04-22
        • 2017-11-08
        • 1970-01-01
        相关资源
        最近更新 更多