Related
I'm trying to implement a simple predicate, that would simply remove items that occur more than once in a list.
For instace, for,
unique([a,b,a,b,c,c,a], R)
should be R = [a,b,c]
unique([], []).
unique([X], [X]).
unique([H|T], [H|R]) :-
not_contains(H, R),
unique(T, R).
unique([H|T], R) :-
contains(H, R),
unique(T, R).
contains(_, []).
contains(X, [X|T]).
not_contains(_, []).
not_contains(X, [H|T]) :-
X \= H,
not_contains(X, T).
I am unsure what I'm doing wrong. If the item is not contained within R, add to it and repeat, and if is, don't add it and proceed with iteration.
A fun way to do it that I just thought of:
nub(L,R):- maplist( p(R), L), length(R,_), !.
p(R,E):- memberchk(E,R).
nub(L,R) makes a unique list R out of an input list L. It assumes R is a non-instantiated variable before the call is made, and L is a fully ground list.
This uses the result list as its own uniqueness accumulator while it is being built!
Testing:
6 ?- nub([a,b,a,b,c,c,a], R).
R = [a, b, c].
The easiest way to make a list unique is just use the built-in sort/2:
unique(Xs,Ys) :- sort(Xs,Ys).
so unique( [c,a,b,a] , Rs ) yields Rs = [a,b,c].
If you want to maintain order, you need to decide on the strategy you want to use — in case of duplicates, which duplicate "wins": First or last?
The "last wins" strategy is the simplest to implement:
unique( [] , [] ) . % the empty list is itself a unique set
unique( [X|Xs] , Ys ) :- % A non-empty list is unique if . . .
contains(X,Xs), % - X is contained within the source list's tail,
!, - and (eliminating the choice point)
unique( Xs, Ys ) . - omitting X, the remainder of the list is (recursively) unique
unique( [X|Xs] , Ys ) :- % Otherwise, the non-empty list is unique if . . .
unique( Xs,[X|Ys] ) . % - adding X to the results, the remainder of the list is (recursively) unique .
Here, unique( [a,b,a,c,a], Rs ) yields Rs = [b,c,a].
If you want to use the "first wins" strategy, you'll be wanting to use a helper predicate with an accumulator that grows the result list in reverse order, which is then reversed. That gives us something like this:
unique( Xs , Ys ) :- unique(Xs,[],Zs), reverse(Zs,Ys) .
unique( [] , Ys , Ys ) . % Source list exhausted? we're done.
unique( [X|Xs] , Ts , Ys ) :- % Otherwise . . .
contains(X,Ts) , % - if X is found in the accumulator,
!, % - eliminate the choice point, and
unique(Xs,Ts,Ys) . % - recurse down, discarding X
unique( [X|Xs] , Ts , Ys ) :- % Otherwise (X is unique) . . .
unique(Xs,[X|Ts],Ys) . % - recurse down, prepending X to the accumulator
And here, unique( [a,b,a,c,a], Rs ) yields Rs = [a,b,c].
You can avoid the use of reverse/2 here, by building the 2 lists (accumulator and final set) in parallel. A trade-off, though: memory for speed:
unique( Xs , Ys ) :- unique(Xs,[],Ys) .
unique( [] , _ , [] ) .
unique( [X|Xs] , Ts , Ys ) :- memberchk(X,Ts), !, unique( Xs, Ts , Ys ) .
unique( [X|Xs] , Ts , [X|Ys] ) :- unique( Xs, [X|Ts] , Ys ) .
You don't really need a contains/2 predicate: the in-built member/2 and memberchk/2 do exactly what you want. member/2 is non-deterministic and will succeed once for every time the item is found in the list; memberchk/2 is non-deterministic and will succeed at most once.
Since this is testing for uniqueness, memberchk/2 is what you'd want, giving you this:
contains(X,Ys) :- memberchk(X,Ys) .
Or you can roll you own (it's trivial):
contains( X , [X|Ys] ) :- ! .
contains( X , [_|Ys] ) :- contains(X,Ys) .
Or even simpler, just a one-liner:
contains( X , [Y|Ys] ) :- X = Y -> true ; contains(X,Ys) .
I'm new to learn the prolog, I want to fulfill the predicate below.
removereverse([[1,5],[5,1],[2,3],[3,2]],List). ---> Input
what I want:
List = [[1,5],[2,3]].
mycode
removes([],[]).
removes([[N1,N2]|T],[[N1,N2]|New]):-
\+member([N1,N2],New),
removes(T,New).
Something like this?
First, lets define a predicate to tell us if a list is duplicated within a list-of-lists. This counts a list as a duplicate if either it or its reverse exists in the target list-of-lists:
duplicated(X,Ls) :- member(X,Ls).
duplicated(X,Ls) :- reverse(X,R), member(R,Ls).
Then we can say:
clean( [] , [] ) .
clean( [X|Xs] , Ys ) :- duplicated(X,Xs), !, clean(Xs,Ys) .
clean( [X|Xs] , [X|Ys] ) :- clean(Xs,Ys) .
That keeps the last "duplicate" found and discard those preceding them in the source list. To keep the first such "duplicate" instead, just change where the recursion occurs:
clean( [] , [] ) .
clean( [X|Xs] , Ys ) :- clean(Xs,Ys), duplicated(X,Xs), !.
clean( [X|Xs] , [X|Ys] ) :- clean(Xs,Ys).
Another approach uses a helper predicate:
This keeps the first:
clean( Xs, Ys ) :- clean(Xs,[],Y0), reverse(Y0,Ys).
clean( [] , Ys, Ys ) .
clean( [X|Xs] , Ts, Ys ) :- duplicated(X,Ts), !, clean(Xs, Ts ,Ys).
clean( [X|Xs] , Ts, Ys ) :- clean(Xs,[X|Ts],Ys).
To keep the last, simply change duplicate(X,Ts) to duplicate(X,Xs). The former checks to see if X exists in the accumulator Ts; the latter checks to see if X exists in the tail of the source list (Xs).
i want to make one list split into list of lists, and skip the 'solid' and separate the list into sublist.
the input and output is below
split_s([A,B,C,solid,D,E,F],X).
X = [[A,B,C],[D,E,F]].
Can anyone help me?
Try something along the following lines. It helps if you decompose your problem. In this case, the heart of the problem is this:
find the longest prefix of a list that doesn't contain the atom solid.
Which you can do like this with a predicate like take_until( List , Separator , Prefix , Remainder ):
take_until( [] , _ , [] , [] ) . % if we hit the end of the source list, we're done.
take_until( [X|Xs] , X , [] , Xs ) . % if we hit the separator, we're done
take_until( [X|Xs] , S , [X|Ps] , Rs ) :- % otherwise...
X \= S , % - when the head of the list is NOT the separator
take_until( Xs , S , Ps , Rs ) % - we take it on to the sublist and keep going.
. %
Once you have that down, the rest is easy:
use the above predicate to extract the first such prefix, then
recurse down on what's left over.
Like this:
split( [] , [] ) . % splitting the empty list results in the empty list.
split( [X|Xs] , [Y|Ys] ) :- % splitting a non-empty list...
take_until( [X|Xs] , solid , Y , R ) , % - get the desired prefix
split(R, , Ys ) % - recurse down on what's left
. % Easy!
The following works for me:
split_s([],[[]]).
split_s([H|T],[[H|XH]|XR]) :- var(H),!,split_s(T,[XH|XR]).
split_s([solid|T],[[]|X]) :- !,split_s(T,X).
split_s([H|T],[[H|XH]|XR]) :- split_s(T,[XH|XR]).
EDIT: moved the cut in the 3rd clause in front of the split.
If you don't want empty lists, then try the following:
split_s([],[]).
split_s([H|T],[[H|XT]|XXT]) :- var(H),!,split_s([[H]|T],[[[H]|XT]|XXT]).
split_s([solid|T],X) :- !,split_s(T,X).
split_s([H],[[H]]) :- !.
split_s([H,M|T],[[H,M|XT]|XXT]) :- var(M),!,split_s([[M]|T],[[[M]|XT]|XXT]).
split_s([H,solid|T],[[H]|XT]) :- !,split_s(T,XT).
split_s([H|T],[[H|XH]|XR]) :- split_s(T,[XH|XR]).
I have a Prolog function that must take in a list (which may include sublists) and return a list that has everything doubled.
For example,
?- doubleAll([1,2,[3,4],5,[6,7,[8],9],10), L).
L = [2,4,[6,8],10,[12,14,[16],18],20).
I was able to double everything when there were no sublists in the list, but when sublists are included I'm having some problems. Here is my code so far:
%L2 is the result of doubling everything in L1.
doubleEverything([],[]).
doubleEverything([H|T], [H2|T2]) :-
atomic(H), H2 is H*2, doubleEverything(T,T2).
doubleEverything([H|T], [H2|T2]) :-
not(atomic(H)), H2 is H*2, doubleEverything(T,T2), doubleEverything(H,T2).
Does anyone see how I can make this work?
Thanks!
Something like this would work:
double( [] , [] ) . % doubling the empty list is...the empty list.
double( [X|Xs] , [XX|XXs] ) :- % if the head of the list is a list,
is_list(X) , % we double it, then double the tail.
! ,
double(X,XX) ,
double(Xs,XXs)
.
double( [X|Xs] , [XX XXs] ) :- % doubling anything else is easy.
XX is X*2 ,
double(Xs,XXs)
.
is_list( X ) :- var(X) , ! , fail .
is_list( [] ) .
is_list( [_|_] ) .
not(atomic(H)), H2 is H*2, doesn't make sense.
Since atomic(H) (should be number(H), really) is already handled, simply recurse:
doubleEverything([H|T], [H2|T2]) :-
doubleEverything(H,H2), doubleEverything(T,T2).
Keep it simple, but remember to test what will happen if neither a number or a list is input...
Having trouble understanding how Prolog works. I'm tryig to write a rule that takes three lists of integers as input (representing sets) and puts the integers that belong to both the first and second list in the third list.
Example:
?-inter([10,20,30,40],[10,50,40,60], List3 )
List3 = [10, 40]
So far I have this, that can recognize if a list contains a certain letter:
mymember(X,[X|T]).
mymember(X,[H|T]) :- mymember(X,T).
There's actually an inbuilt library to sort that all out for you, known as ordsets.
inter(X, Y, Z) :-
list_to_ord_set(X, L1),
list_to_ord_set(Y, L2),
ord_intersection(L1, L2, Z).
Using your example input you get the following
| ?- inter([10,20,30,40],[10,50,40,60],X).
X = [10,40] ? ;
no
inter(Xs, Ys, Zs) will be true when each element in Zs also is in Xs and in Ys.
But Zs are unknown, then a more constructive approach is required.
Here it is: iterate on Xs and store in Zs each element that is in Ys.
An example of iteration is mymember/2, you can see that it requires a recursive predicate.
The other idiomatic part of the above statement is store in Zs, Prolog has a peculiar way to do such things, using pattern matching.
inter([X|Xs], Ys, [X|Zs]) :-
mymember(X, Ys), inter(Xs, Ys, Zs).
You will need to complete inter/3 with other 2 clauses: base recursion, i.e. when all Xs elements have been processed, and the case where X is not a member of Ys.
Try something like this, using the builtins member/2 and setof\3:
set_intersection( As , Bs , Xs ) :-
set_of( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
One should note that this will fail if the lists As and Bs have no elements in common. An alternative would be use findall/3 rather than set_of/3. findall/3 will hand back and empty list rather than failure if the goal is not satisfied:
set_intersection( As , Bs , Xs ) :-
findall( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
However findall/3 returns a bag (duplicates are allowed) rather than a set (no duplicates allowed), so if your two source lists aren't sets, you won't get a set out.
member/2 is a builtin predicate that unifies its first argument with an element of the list — the equivalent of
member(X,[X|_).
member(X,[_|Xs) :- member(X,Xs) .
And, finally, as #chac noted in his answer, you can recursively traverse the list.
set_intersection( [] , _ , [] ) . % the intersection of the empty set with anything is the empty set.
set_intersection( [A|As] , Bs , [A|Xs] ) :- % if the list is non-empty,
member(A,Bs) , % - and A is a member of the 2nd set
! , % - we cut off alternatives at this point (deterministic)
set_intersection( As , Bs , Xs ) % - and recurse down on the tail of the list.
.
set_intersection( [_|As] , Bs , Xs ) :- % if the list is non-empty, and A is NOT a embmer of the 2nd set
set_intersection( As , Bs , Xs ) % we just recurse down on the tail of the list.
.
#chac's technique builds the result list as he goes, something like:
[a|X]
[a,b|X]
[a,b,c|X]
The final unification, the special case of the empty list unifies the unbound tail of the list with [] making the list complete, so the final [a,b,c|X] becomes
[a,b,c]
A little prolog magic. An alternative that might be easier to understand is to use a worker predicate with an accumulator:
%
% set_intersection/3: the public interface predicate
%
set_intersection( As , Bs , Xs ) :-
set_intersection( As , Bc , [] , T ) % we seed our accumulator with the empty list here
.
%
% set_intersection/4: the private worker bee predicate
%
set_intersection( [] , _ , T , Xs ) :- % since our accumulator is essentially a stack
reverse(T,Xs) % we need to reverse the accumulator to
. % put things in the expected sequence
set_intersection( [A|As] , Bs , T , Xs ) :-
member( A, Bs ) ,
! ,
T1 = [A|T] ,
set_intersection( As , Bs , T1 , Xs )
.
set_intersection( [_|As] , Bs , T , Xs ) :-
set_intersection( As , Bs , T , Xs )
.