序言:创建另一个列表的频率列表

时间:2019-05-31 14:05:39

标签: prolog swi-prolog

因此,我编写了一个程序,该程序以2个整数和一个整数列表的形式从.txt文件中读取输入:第一个整数是列表的长度,第二个是不同元素的数量,列表就是有问题的列表。

然后我想为元素创建一个频率列表,如下所示:

List = [1, 2, 3, 1, 3, 2, 3, 1],
FreqList = [3, 2, 3].

这是我的代码:

% Create random list
createList(List) :-
length(List, 10), 
maplist(random(0,4), List).

% Count the frequency of an element:
countElement(_, [], 0) :- !.
countElement(_, [], _).
countElement(Element, [Element|Tail], Counter) :-
    countElement(Element, Tail, Counter2),
    Counter is Counter2 + 1.
countElement(Element, [_|Tail], Counter) :-
    countElement(Element, Tail, Counter).

% Create frequency list:
createFreqList(_, _, Numbers, [], CurrentNumber) :-
    Numbers = CurrentNumber.
createFreqList(List, Length, Numbers, [Head|Tail], CurrentNumber) :-
    Numbers \= CurrentNumber,
    countElement(CurrentNumber, List, Head),
    CurrentNumber2 is CurrentNumber + 1,
    createFreqList(List, Length, Numbers, Tail, CurrentNumber2).

frequency(List, FreqList) :-
    createList(List),
    Numbers2 is 4,
    createFreqList(List, 10, Numbers2, FreqList, 1).

因此,在第一次执行时,程序运行正常,并输出正确的频率列表。但是,如果我输入“;”,而不是给我“ false”,它会再次运行,输出错误的频率列表,并且只要我按“;”,它就会重复一次。

2 个答案:

答案 0 :(得分:0)

以防万一您不想重新发明轮子。

有一个称为库(集合)的准标准。但是库(聚合)也可以在ISO核心标准bagof / 3之上实现,这也可以帮助您:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.6)

?- aggregate(count, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), R).
X = 1,
R = 3 ;
X = R, R = 2 ;
X = R, R = 3.

?- bagof(hit, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), L), length(L, R).
X = 1,
L = [hit, hit, hit],
R = 3 ;
X = R, R = 2,
L = [hit, hit] ;
X = R, R = 3,
L = [hit, hit, hit].

或在另一个Prolog系统中:

Jekejeke Prolog 3, Runtime Library 1.3.7 (May 23, 2019)

?- use_module(library(advanced/aggregate)).
% 3 consults and 0 unloads in 110 ms.
Yes

?- use_module(library(basic/lists)).
% 0 consults and 0 unloads in 0 ms.
Yes

?- aggregate(count, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), R).
X = 1,
R = 3 ;
X = 2,
R = 2 ;
X = 3,
R = 3

?- bagof(hit, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), L), length(L, R).
X = 1,
L = [hit,hit,hit],
R = 3 ;
X = 2,
L = [hit,hit],
R = 2 ;
X = 3,
L = [hit,hit,hit],
R = 3

答案 1 :(得分:0)

我可能会做这样的事情:

frequencies(Xs, Fs) :-
  msort(Xs,Sorted),
  glob( Sorted, [], Fs ).

glob( [], Fs, Fs ).
glob( [X|Xs], [X:N|Ts], Fs ) :-
  !,
  N1 is N+1,
  glob(Xs, [X:N1|Ts], Fs ).
glob( [X|Xs], Ts, Fs ) :-
  glob(Xs, [X:1|Ts], Fs).

使用msort/2按顺序排列列表。结果列表按键值{[ 3:123, 2:25, 1:321 ]降序排列。

您还可以执行以下操作:

frequencies(Xs, Fs) :- frequencies( Xs, [], Fs ).

frequencies( [],     Fs, Fs ).
frequencies( [X|Xs], Ts, Fs ) :-
  tote( X, Ts, T1),
  frequencies(Xs, T1, Fs).

tote( X, Ts, Fs ) :-
  append( Pfx, [X:N|Sfx], Ts),
  !,
  N1 is N+1,
  append( Pfx, [X:N1|Sfx], Fs).
tote( X, Ts, [X:1|Ts] ).

我怀疑原始列表的一次性排序可能比重复扫描累加器列表更快。