Reputation: 312
i'm having problems with this subject in Prolog. The thing is that I want to count the number of repeated elements appearing in a list, and I also want to fill, in another list with 1, for each appearance of duplicated elements and a 0 if is not duplicated, e.g.
I have a list like this: [420,325,420,582,135,430,582], and the result should be [1,0,1,1,0,0,1].
I've tried some code snippets and it's driving me nuts.
The last code i've tried is:
count_duplicates([],[]).
count_duplicates([Head|Tail],[1|LS]):-
member(Head,Tail),
count_duplicates([Tail|Head],LS).
count_duplicates([Head|Tail],[0|LS]):-
\+ member(Head,Tail),
count_duplicates([Tail|Head],LS).
this predicate receive a list and have to generate the result list
Thanks in advance
Upvotes: 0
Views: 3088
Reputation: 5645
You can try this :
count_duplicate(In, Out) :-
maplist(test(In), In, Out).
test(Src, Elem, 1) :-
select(Elem, Src, Result),
member(Elem, Result).
test(_Src, _Elem, 0).
EDIT Without maplist, you can do
count_duplicate(In, Out) :-
test(In, In, Out).
test(_, [], []).
test(In, [Elem | T], [R0 | R]) :-
select(Elem, In, Rest),
( member(Elem, Rest) -> R0 = 1; R0 = 0),
test(In, T, R).
Upvotes: 1
Reputation: 60034
I would rewrite using some of list processing builtins available:
count_duplicates(L, R) :-
maplist(check(L), L, R).
check(L, E, C) :-
aggregate(count, member(E, L), Occurs),
( Occurs > 1 -> C = 1 ; C = 0 ).
with that
?- count_duplicates([420,325,420,582,135,430,582],L).
L = [1, 0, 1, 1, 0, 0, 1].
About your code, I think it's simple to get termination:
count_duplicates([],[]).
count_duplicates([Head|Tail],[1|LS]):-
member(Head,Tail),
count_duplicates(Tail,LS).
count_duplicates([Head|Tail],[0|LS]):-
\+ member(Head,Tail),
count_duplicates(Tail,LS).
Note I corrected the recursive calls, and consider that could be done in a slightly more efficient way (both source and runtime) using the if .. then .. else .. construct.
count_duplicates([],[]).
count_duplicates([Head|Tail],[R|LS]):-
( member(Head,Tail) -> R = 1 ; R = 0 ),
count_duplicates(Tail,LS).
it's cleaner, isn't it? member/2 it's called just once, that's a big gain, and consider using memberchk/2 instead of member/2.
But that code fails to tag as multiple the last occurrence.
Upvotes: 0