Search code examples
prolog

How do I implement in Prolog the predicate list_for_set


How do I implement in Prolog the predicate list_for_set(Xs, Cs) where Cs is a list that contains the same elements as Xs, in the order of its first occurrence, but whose number of occurrences is only 1. For example, the query

? - list_for_set([1, a, 3.3, a, 1.4], Cs).

it happens only for Cs = [1, a, 3,4]. The consultation

? - list_for_set ([1, a, 3,3, a, 1,4], [a, 1,3,4])

must fail.

The Cs list of the previous statement will be called a set list, that is, a list with only one occurrence of each element.


Solution

  • Ok, there is some trickery involved.

    foofilter([],_,_-T) :- T=[]. % close difflist
    
    foofilter([L|Ls],Seen,H-T) :-
       member(L,Seen),
       !,
       foofilter(Ls,Seen,H-T).
    
    foofilter([L|Ls],Seen,H-T) :-
       \+member(L,Seen),
       !,
       T=[L|NewT],
       foofilter(Ls,[L|Seen],H-NewT).
    
    :-begin_tests(filter).
    
    data([1, a, 3, 3, a, 1, 4]).
    
    test(one) :- data(L),
                 DiffList=[[]|T]-T,  % Assume [] is never in L
                 foofilter(L,[],DiffList),
                 DiffList=[_|Result]-_,
                 format("~q ==> ~q\n",[L,Result]),
                 Result = [1,a,3,4].
    
    :-end_tests(filter).
    
    rt :- run_tests(filter).
    

    Run tests:

    ?- rt.
    % PL-Unit: filter [1,a,3,3,a,1,4] ==> [1,a,3,4]
    . done
    % test passed
    true.
    

    Someone will probably come up with a one-liner.