0

I'm new to learn Prolog, I want to fulfill the predicate below, I have no idea how I implement this

count([9,9,2,2,1],X). -- input

X = [1-1,2-2,9-2].

[X-Y] = X is the value, Y is the counter.

lilRed
  • 55
  • 5

3 Answers3

0

A possible solution

count(L,LC):-
    findall(X,member(X,L),LX),
    sort(LX,LS),
    maplist(get_count(L),LS,C),
    maplist(pair,LS,C,LC).

pair(X,Y,X-Y).
get_count(L,El,N):-
    findall(X,nth0(X,L,El),LN),
    length(LN,N).

?- A= [1,2,1,4], count(A,B).
A = [1, 2, 1, 4],
B = [1-2, 2-1, 4-1]
damianodamiano
  • 2,528
  • 2
  • 13
  • 21
0
count_elements(Lst, LstCount) :-
    % "sort" also removes duplicates
    sort(Lst, LstSorted),
    findall(Elem-Count, (
        member(Elem, LstSorted), elem_in_list_count(Elem, Lst, Count)
    ), LstCount).
    
elem_in_list_count(Elem, Lst, Count) :-
    aggregate_all(count, member(Elem, Lst), Count).

Result in swi-prolog:

?- time(count_elements([9, 9, 2, 2, 1], Pairs)).
% 61 inferences, 0.000 CPU in 0.000 seconds (96% CPU, 528143 Lips)
Pairs = [1-1,2-2,9-2].

Here is a logically-pure version (in which the final sort needed the most coding effort):

:- use_module(library(reif)).

count_elements_pure(Lst, LstCountSorted) :-
    count_elem_pairs_(Lst, Lst, [], LstCount),
    keysort_pure(LstCount, LstCountSorted).

count_elem_pairs_([], _, _, []).
count_elem_pairs_([H|T], Lst, LstUnique, LstCount) :-
    memberd_t(H, LstUnique, Bool),
    ( Bool == true -> count_elem_pairs_(T, Lst, LstUnique, LstCount)
    ; list_elem_count(Lst, H, Count),
      % Add pair
      LstCount = [H-Count|LstCount0],
      count_elem_pairs_(T, Lst, [H|LstUnique], LstCount0)
    ).

% Count elements in list, with logical purity
list_elem_count(Lst, Elem, Count) :-
    list_elem_count_(Lst, Elem, Count).

list_elem_count_([], _Elem, 0).
list_elem_count_([H|T], Elem, Count) :-
    list_elem_count_(T, Elem, Count0),
    if_(H = Elem, Count is Count0 + 1, Count0 = Count).


lowest_pair(Lst, Elem) :-
    Lst = [H|T],
    lowest_pair_(T, H, Elem).

lowest_pair_([], E, E).
lowest_pair_([H|T], P, L) :-
    H = HKey-_,
    P = PKey-_,
    % The key is not limited to an integer
    when((nonvar(HKey), nonvar(PKey)), compare(Comp, HKey, PKey)),
    lowest_pair_comp_(Comp, T, H, P, L).

lowest_pair_comp_(<, T, H, _, L) :-
    lowest_pair_(T, H, L).

lowest_pair_comp_(>, T, _, P, L) :-
    lowest_pair_(T, P, L).


keysort_pure(Lst, LstSorted) :-
    keysort_pure_(Lst, LstSorted).

keysort_pure_([], []).
keysort_pure_([H|T], [E|Sorted]) :-
    lowest_pair([H|T], E),
    % Don't need to repeat the if_/3 checks
    select_once_eqeq([H|T], E, Rest),
    keysort_pure_(Rest, Sorted).

select_once_eqeq(Lst, Elem, Rest) :-
    Lst = [H|T],
    select_once_eqeq_(T, H, Elem, Rest).

select_once_eqeq_(Tail, Head, Elem, Rest) :-
    Elem == Head, !,
    Rest = Tail.

select_once_eqeq_([Head2|Tail], Head, Elem, [Head|Rest]) :-
    select_once_eqeq_(Tail, Head2, Elem, Rest).

Result in swi-prolog:

?- time(count_elements_pure([9, 9, 2, 2, 1], Pairs)).
% 111 inferences, 0.000 CPU in 0.000 seconds (95% CPU, 1134876 Lips)
Pairs = [1-1,2-2,9-2].

The combinations multiply quickly, so here is just a taste:

?- count_elements_pure([A, B], Pairs).
A = B,
Pairs = [B-2] ;
Pairs = [B-1,A-1],
dif(B,A),
when((nonvar(B),nonvar(A)),compare(<,B,A)) ;
Pairs = [A-1,B-1],
dif(B,A),
when((nonvar(B),nonvar(A)),compare(>,B,A)).
brebs
  • 3,462
  • 2
  • 3
  • 12
  • Why use `keysort_pure/2` if it can increase both the size of individual answers and the number of answers? – repeat Apr 03 '22 at 16:50
  • What do you think is best? I seem to have the options of keysort_pure (done), or ignore the sorting that the original question specified. – brebs Apr 03 '22 at 16:54
  • Good point! The way I saw it is that a spec consisting of nothing but a single data point could not possibly demand a certain order:) – repeat Apr 03 '22 at 17:49
  • After a bit of thinking about it... the keysort-part is not central to the question and it is challenging to get it right (while staying pure), so I'd rather scrap it. As is, your keysort_pure may lose purity when it is confronted with keys that turn out to be compound terms. Fixing this certainly is doable, but, again, I feel it is somewhat beside the core of this question. – repeat Apr 03 '22 at 19:31
0

In SWI-Prolog, you can also use clumped/2 as follows:

% count(+List, -Pairs)

  count(List, Pairs) :-
      msort(List, Sorted),
      clumped(Sorted, Pairs).

Examples:

?- count([9, 9, 2, 2, 1], P).
P = [1-1, 2-2, 9-2].

?- count([X,Y,X,X,Y,Z,X,Z,W,Z], P).
P = [X-4, Y-2, Z-3, W-1].
slago
  • 5,025
  • 2
  • 10
  • 23