Eliminate consecutive duplicates of list elements with prolog - prolog

The original problem was to come up with a way to get the following
remove([a,a,a,b,q,q,q,q,e,e,e]),X)
X = [a,b,q,e]

We can solve this problem by one iteration along the list. At any point in the list we check the current element and the next element, if they are the same then we ignore the current element, else if they are different we take the current element.
rm_dup([], []).
rm_dup([X], [X]).
rm_dup([X1, X2 | Xs], [X1 | Ys]) :-
dif(X1, X2), rm_dup([X2|Xs], Ys).
rm_dup([X, X | Xs], Ys) :-
rm_dup([X | Xs], Ys).
The first and second clauses are base clauses in which there are no duplicate elements. The third and fourth clauses are recursive rules.
In third clause we state that if the input list has two values X1 and X2 and they are different dif(X1, X2), then keep the current value.
In fourth clause if we have same consecutive values then we ignore the current value.
The third and fourth clauses are mutually exclusive and hence to make the predicate deterministic it is better to combine them as follows
rm_dup([X], [X]) :- !.
rm_dup([X1, X2 | Xs], Ys) :-
dif(X1, X2) -> (rm_dup([X2 | Xs], Ys1), Ys = [X1 | Ys1]);
rm_dup([X2 | Xs], Ys).
Even better is to just use equality as a condition and flip the then and else clauses.
rm_dup([X], [X]) :- !.
rm_dup([X1, X2 | Xs], Ys) :-
X1 = X2 -> rm_dup([X2 | Xs], Ys);
rm_dup([X2 | Xs], Ys1), Ys = [X1 | Ys1].

Kinda long, but this solved it.
delete(_,[],[]).
delete(X,[X|T],R):- delete(X,T,R).
delete(X,[H|T],[H|R]) :- delete(X,T,R).
remove([],[]).
remove([H|T], [H|R]) :-
member(H,T),!,
delete(H,T,R1),
remove(R1,R).
remove([H|T],[H|R]):-
remove(T,R).

You can simply use sort.
First: In the base class if the List are empty stop.
Second: In the second predicate, take the list and sort it. Display the answer in K.
remove_extras([],[]).
remove_extras([H|T],K):-
sort([H|T], K).
?-remove_extras([a,a,a,b,q,q,q,q,e,e,e],X).
X = [a, b, e, q]
?-remove_extras([1,3,2,5,1,6,1,2,7],X).
X = [1, 2, 3, 5, 6, 7]
If you don't want to use sort, you can use the following predicates:
Remove duplicates checks for elements existing more than once and keeps them in the list.
First: The base case says that if the lists are empty stop.
Second: The second predicate checks if an element exist in the remaining list (member) then don't add it to the final list.
Third: The third predicate says, if the element is in not the remaining list then add it to the final list.
remove_duplicates([],[]).
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
remove_duplicates([H | T], [H|T1]) :-
\+ member(H, T),
remove_duplicates( T, T1).

Related

PROLOG. Get all objects from list matching a pattern

I am a beginner in prolog and i have a problem with getting objects from list matching a pattern.
If i have a list [1,2,3,4,5,1,1] . I want to use a predicate selectAll(Elem,List,X).
Where i use ?- selectAll(1,[1,2,3,4,5,1,1],X), I get X =[1,1,1], but i also want to use data structures inside the predicate, not only atoms.
I originally wrote this predicate for getting all matching elements, but it works only for simple cases, where only atoms are used:
selectAll(_, [], []).
selectAll(X, [X | LIST], [X | RES]):-
selectAll(X, LIST, RES),!.
selectAll(X, [H | LIST], RES):-
selectAll(X, LIST, RES).
When i use this test predicate, everything works fine. I get X=[1,1,1], the result i want.
test_select_all:-
selectAll(1, [1,2,3,4,5,1,1], X),
write(X),nl,
fail.
I have a data structure called kv_pairs(A,B) where A and B contain atoms of any type.
So when i use the selectAll predicate for this datatype, i get unwanted results. X = [kv_pair(1,a)]. It selects only 1 element at most.
test_select_all_dict:-
selectAll(kv_pair(1,_), [kv_pair(1, a), kv_pair(1, b),kv_pair(3, jkak), kv_pair(15, asdjk), kv_pair(1, c)], X),
write(X),nl,
fail.
I then created this predicate, specifically for finding list elements, where all types are kv_pairs
selectAll(_, [], []).
selectAll(kv_pair(Arg, _), [kv_pair(Arg,_) | LIST], [kv_pair(Arg,_) | RES]):-
selectAll(kv_pair(Arg, _), LIST, RES),!.
selectAll(kv_pair(Arg, X), [kv_pair(A, B) | LIST], RES):-
selectAll(kv_pair(Arg, X), LIST, RES).
But then i get also unwanted results.
X = [kv_pair(1,_8378),kv_pair(1,_8396),kv_pair(1,_8426)]
How can i get
X = [kv_pair(1,a),kv_pair(1,b),kv_pair(1,c)]?
Any help would be appreciated.
You can use the ISO predicate subsumes_term/2 to undo bindings after unification:
select_all(Pattern, List, Result) :-
select_all_loop(List, Pattern, Result).
select_all_loop([], _, []).
select_all_loop([X|Xs], P, R) :-
( subsumes_term(P, X)
-> R = [X|Ys]
; R = Ys ),
select_all_loop(Xs, P, Ys).
Examples:
?- select_all(kv_pair(1,_), [kv_pair(1,a), kv_pair(1,b), kv_pair(3,c), kv_pair(4,d), kv_pair(1,c)], R).
R = [kv_pair(1, a), kv_pair(1, b), kv_pair(1, c)].
?- select_all(p(1,Y), [p(1,a), p(1,b), p(2,b), p(1,c)], L).
L = [p(1, a), p(1, b), p(1, c)].
?- select_all(p(X,b), [p(1,a), p(1,b), p(2,b), p(1,c)], L).
L = [p(1, b), p(2, b)].

Rule matching regarding lists in SWI Prolog

Recently I started learning Prolog and as an exercise I tried to implement a predicate penultimate/2 giving the penultimate element of a list that would not backtrack.
This problem is trivial when one use cuts, but I tried to implement a predicate in a similar way to SWI-Prolog implementation of last/2 predicate that would not use cuts:
penultimate([X1, X2 | Rest], Elem) :-
penultimate_([X1, X2 | Rest], X1, X2, Elem).
penultimate_([], X1, _, X1).
penultimate_([_], _, X2, X2).
penultimate_([X1, X2 | Rest], _, _, Penultimate) :-
penultimate_(Rest, X1, X2, Penultimate).
This code works as expected when the length of the list is even, but when fed with a list of odd length, I get the following result:
?- penultimate([1,2,3], X).
X = 2 ;
false.
The only reason why this happens that I can come up with is that the SWI-Prolog matching system treats the rule in my program as a possibility for matching against a one-element list even though the list in the rule head requires at least 2 elements. Is this correct?
Try:
penultimate([X1, X2 | Rest], Penultimate) :-
penultimate(Rest, X1, X2, Penultimate).
penultimate([], Penultimate, _, Penultimate).
penultimate([X3| Rest], _, X2, Penultimate) :-
penultimate([X2, X3| Rest], Penultimate).
Sample calls:
| ?- penultimate([1,2,3,4,5], P).
P = 4
yes
| ?- penultimate([1,2,3,4], P).
P = 3
yes
| ?- penultimate([1,2,3], P).
P = 2
yes
| ?- penultimate([1,2], P).
P = 1
yes
| ?- penultimate([1], P).
no
Indexing on most Prolog systems can distinguish between an empty list (an atom) or a non-empty list (a compound term) but usually would not perform deep-indexing in a list.

Remove duplicates in backtracking

I have a predicate next which essentially removes numbers from a list, in the attempt to decrease the overall size of the list.
So for example I have a list:
[3,2,1]
next will remove certain values from the list, so it'll return something like this
[3,2] or [3,1] or [3] or [2,1] etc
I'm running a script to find all possible moves:
findall(T, next([2,3], T), U).
The problem is for a list which repeats values such as:
L = [1,1,1,1].
the call
findall(T, next([1,1,1,1], T), U).
will unify U with [[1,1,1], [1,1,1], [1,1,1], [1,1,1]]
Is there a way to make the Prolog understand that it is returning the same output multiple times?
next([_ | T], T).
next([H | Tin], [H | Tout]) :-
next(Tin, Tout).
It seems a works for setof/3
setof(T, next([1,1,1,1], T), U)
--- EDIT ---
The OP say
This does do it but it's a bit of a hacky fix, I'm looking for an alteration in the next predicate
I don't think the following it's a great solution and I suspect that it's better use setof/3 with the original next/2 but...
next(Lin, LLout) :-
nextH(Lin, [], LLout).
nextH([], _, []).
nextH([H | Tin], Pre, LLout1) :-
append(Pre, Tin, L),
append(Pre, [H], Pre0),
nextH(Tin, Pre0, LLout0),
( member(L, LLout0)
-> LLout1 = LLout0
; LLout1 = [L | LLout0] ).
--- EDIT 2 ---
The OP ask
how could you use setof in the next predicate?
If you use your original next/2 predicate that generate singles lists (but I recall it nextH, "next helper")
nextH([_ | T], T).
nextH([H | Tin], [H | Tout]) :-
nextH(Tin, Tout).
the next/2 predicate that return a list of unique list become simply (using setof/3)
next(Lin, LLout) :-
setof(Lout, nextH(Lin, Lout), LLout).

How to check if a list is a non-empty sublist of another list in Prolog

I am trying to create an included_list(X,Y) term that checks if X is a non-empty sublist of Y.
I already use this for checking if the elements exist on the Y list
check_x(X,[X|Tail]).
check_x(X,[Head|Tail]):- check_x(X,Tail).
And the append term
append([], L, L).
append([X | L1], L2, [X | L3]) :- append(L1, L2, L3).
to create a list, in order for the program to finish on
included_list([HeadX|TailX],[HeadX|TailX]).
but I am having problems handling the new empty list that I am trying to create through "append" (I want to create an empty list to add elements that are confirmed to exist on both lists.)
I have found this
sublist1( [], _ ).
sublist1( [X|XS], [X|XSS] ) :- sublist1( XS, XSS ).
sublist1( [X|XS], [_|XSS] ) :- sublist1( [X|XS], XSS ).
but it turns true on sublist([],[1,2,3,4)
Since you're looking for a non-contiguous sublist or ordered subset, and not wanting to include the empty list, then:
sub_list([X], [X|_]).
sub_list([X], [Y|T]) :-
X \== Y,
sub_list([X], T).
sub_list([X,Y|T1], [X|T2]) :-
sub_list([Y|T1], T2).
sub_list([X,Y|T1], [Z|T2]) :-
X \== Z,
sub_list([X,Y|T1], T2).
Some results:
| ?- sub_list([1,4], [1,2,3,4]).
true ? a
no
| ?- sub_list(X, [1,2,3]).
X = [1] ? a
X = [2]
X = [3]
X = [1,2]
X = [1,3]
X = [1,2,3]
X = [2,3]
(2 ms) no
| ?- sub_list([1,X], [1,2,3,4]).
X = 2 ? a
X = 3
X = 4
(2 ms) no
Note that it doesn't just tell you if one list is a sublist of another, but it answers more general questions of, for example, What are the sublists of L? When cuts are used in predicates, it can remove possible valid solutions in that case. So this solution avoids the use of cut for this reason.
Explanation:
The idea is to generate a set of rules which define what a sublist is and try to do so without being procedural or imperative. The above clauses can be interpreted as:
[X] is a sublist of the list [X|_]
[X] is a sublist of the list [Y|T] if X and Y are different and [X] is a sublist of the list T. The condition of X and Y different prevents this rule from overlapping with rule #1 and greatly reduces the number of inferences required to execute the query by avoiding unnecessary recursions.
[X,Y|T1] is a sublist of [X|T2] if [Y|T1] is a sublist of T2. The form [X,Y|T1] ensures that the list has at least two elements so as not to overlap with rule #1 (which can result in any single solution being repeated more than once).
[X,Y|T1] is a sublist of [Z|T2] if X and Z are different and [X,Y|T1] is a sublist of T2. The form [X,Y|T1] ensures that the list has at least two elements so as not to overlap with rule #2, and the condition of X and Z different prevents this rule from overlapping with rule #3 (which can result in any single solution being repeated more than once) and greatly reduces the number of inferences required to execute the query by avoiding unnecessary recursions.
Here is what you an do:
mysublist(L,L1):- sublist(L,L1), notnull(L).
notnull(X):-X\=[].
sublist( [], _ ).
sublist( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
sublist( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).
Taking a reference from this:
Prolog - first list is sublist of second list?
I just added the condition to check if it was empty beforehand.
Hope this helps.
If order matters. Example [1,2,3] is sublist of [1,2,3,4] but [1,3,2] not.
You can do something like this.
sublist([],L).
sublist([X|L1],[X|L2]):- sublist(L1,L2)
I would use append :
sublist(X, []) :-
is_list(X).
sublist(L, [X | Rest]) :-
append(_, [X|T], L),
sublist(T, Rest).
Basically we can check if M is a sublist of L if M exists in L by appending something on its back and/or its front.
append([], Y, Y).
append([X|XS],YS,[X|Res]) :- append(XS, YS, Res).
sublist(_, []).
sublist(L, M) :- append(R, _, L), append(_, M, R).

Prolog: Matching One or More Anonymous Variables

[_, [ X , _ ],_] will match a list like [d, [X,a], s]. Is there a way to match it to any pattern where there is one or more anonymous variables? ie. [[X,a],s] and [[d,a],[p,z], [X,b]] would match?
I am trying to write a program to count the elements in a list ie. [a,a,a,b,a,b] => [[a,4],[b,2]] but I am stuck:
listcount(L, N) :- listcountA(LS, [], N).
listcountA([X|Tail], [? [X, B], ?], N) :- B is B+1, listcountA(Tail, [? [X,B] ?], N).
listcountA([X|Tail], AL, N) :- listcountA(Tail, [[X,0]|AL], N).
Thanks.
A variable match a term, and the anonimus variable is not exception. A list is just syntax sugar for a binary relation, between head and tail. So a variable can match the list, the head, or the tail, but not an unspecified sequence.
Some note I hope will help you:
listcount(L, N) :- listcountA(LS, [], N).
In Prolog, predicates are identified by name and num.of.arguments, so called functor and arity. So usually 'service' predicates with added arguments keep the same name.
listcountA([X|Tail], [? [X, B], ?], N) :- B is B+1, listcountA(Tail, [? [X,B] ?], N).
B is B+1 will never succeed, you must use a new variable. And there is no way to match inside a list, using a 'wildcard', as you seem to do. Instead write a predicate to find and update the counter.
A final note: usually pairs of elements are denoted using a binary relation, conveniently some (arbitrary) operator. For instance, most used is the dash.
So I would write
listcount(L, Counters) :-
listcount(L, [], Counters).
listcount([X | Tail], Counted, Counters) :-
update(X, Counted, Updated),
!, listcount(Tail, Updated, Counters).
listcount([], Counters, Counters).
update(X, [X - C | R], [X - S | R]) :-
S is C + 1.
update(X, [H | T], [H | R]) :-
update(X, T, R).
update(X, [], [X - 1]). % X just inserted
update/3 can be simplified using some library predicate, 'moving inside' the recursion. For instance, using select/3:
listcount([X | Tail], Counted, Counters) :-
( select(X - C, Counted, Without)
-> S is C + 1
; S = 1, Without = Counted
),
listcount(Tail, [X - S | Without], Counters).
listcount([], Counters, Counters).
I'll preface this post by saying that if you like this answer, consider awarding the correct answer to #chac as this answer is based on theirs.
Here is a version which also uses an accumulator and handles variables in the input list, giving you the output term structure you asked for directly:
listcount(L, C) :-
listcount(L, [], C).
listcount([], PL, PL).
listcount([X|Xs], Acc, L) :-
select([X0,C], Acc, RAcc),
X == X0, !,
NewC is C + 1,
listcount(Xs, [[X0, NewC]|RAcc], L).
listcount([X|Xs], Acc, L) :-
listcount(Xs, [[X, 1]|Acc], L).
Note that listcount/2 defers to the accumulator-based version, listcount/3 which maintains the counts in the accumulator, and does not assume an input ordering or ground input list (named/labelled variables will work fine).
[_, [X, _], _] will match only lists which have 3 elements, 1st and 3rd can be atoms or lists, second element must be list of length 2, but i suppore you know that. It won't match to 2 element list, its better to use head to tail recursion in order to find element and insert it into result list.
Heres a predicate sketch, wich i bet wont work if copy paste ;)
% find_and_inc(+element_to_search, +list_to_search, ?result_list)
find_and_inc(E, [], [[E, 1]]);
find_and_inc(E, [[E,C]|T1], [[E,C1]|T2]) :- C1 is C+1;
find_and_inc(E, [[K,C]|T1], [[K,C]|T2]) :- find_and_inc(E, T1, T2).

Resources