I'm trying to create a predicate in Prolog that takes a list and returns only one copy of the adjacent duplicates of the list.
for example:
?- adj_dups([a,b,a,a,a,c,c],R).
R=[a,c]
I think I need two base cases:
adj_dups([],[]). % if list is empty, return empty list
adj_dups([X],[]). % if list contains only one element, return empty list (no duplicates).
then for the recursive part, I need to compare the head with the head of the tail, and then go recursively on the tail of the list.
This is what I came up with so far, but it doesn't work!
adj_dups([X,X|T],[X|R]):- adj_dups([X|T],R). % if the list starts with duplicates
adj_dups([X,Y|T],R):- X \= Y, adj_dups([X|T],R). % if the list doesn't start wih duplicates
How can I fix it so I can get the right result?
Edit:
I'll list some examples to help you all understand my problem.
How the code supposed to behave:
?- adj_dups([a,c,c,c,b],R).
R = [c]
?- adj_dups([a,b,b,a,a],R).
R = [b,a]
?- adj_dups([a,b,b,a],R).
R = [b]
How my code is behaving:
?- adj_dups([a,c,c,c,b],R).
R = []
?- adj_dups([a,b,b,a,a],R).
R = [a,a]
?- adj_dups([a,b,b,a],R).
R = [a]
Thank you.
I find ambiguous this specification
only one copy of the adjacent duplicates of the list
as it doesn't clarify what happens when we have multiple occurrences of the same duplicate symbol.
adj_dups([],[]).
adj_dups([X,X|T],[X|R]) :-
skip(X,T,S),
adj_dups(S,R),
\+ memberchk(X,R),
!.
adj_dups([_|T],R) :- adj_dups(T,R).
skip(X,[X|T],S) :- !, skip(X,T,S).
skip(_,T,T).
This yields
?- adj_dups([a,a,c,c,a,a],R).
R = [c, a].
Comment the + memberchk line to get instead
?- adj_dups([a,a,c,c,a,a],R).
R = [a, c, a].
Let's look at what happens when you try a simpler case:
adj_dups([a,b,b,a],R).
The first three predicates don't match, so we get:
adj_dups([X,Y|T],R):- X \= Y, adj_dups([X|T],R).
This is the problematic case: X is bound to a, Y is bound to b.
It will then call adj_dups([a,b,a],R), binding T to [b,a], which only has a single b. Effectively, you have now removed the duplicate b from the list before it could be processed.
Let's create a few auxiliary predicates first - especially a predicate that filters an element from a list. Then, in the recursive part, there are two cases:
If the first element occurs in the tail of the list being processed, it is duplicated; we need to return that first element followed by the processed tail. Processing the tail consists of removing that first element from it, then check the tail for duplicates.
The second case is much simpler: if the first element does not occur in the tail, we simply apply adj_dups to the tail and return that. The first element was never duplicated, so we forget about it.
% Filter the element X from a list.
filter(X,[],[]).
filter(X,[X|T],R) :- filter(X,T,R).
filter(X,[Y|T],[Y|R]) :- X \= Y, filter(X,T,R).
% Return "true" if H is NOT a member of the list.
not_member(H,[]).
not_member(H,[H|T]):-fail.
not_member(H,[Y|T]):-H \= Y, not_member(H,T).
% Base cases for finding duplicated values.
adj_dups([],[]). % if list is empty, return empty list
adj_dups([X],[]). % if list contains only one element, return empty list (no duplicates).
% if H1 is in T1 then return the H1 followed by the adj_dups of (T1 minus H1).
% if H1 is not in T1 then return the adj_dups of T1.
adj_dups([H1|T1],[H1|T3]):-member(H1,T1), filter(H1,T1,T2), adj_dups(T2,T3).
adj_dups([H1|T1],T3):-not_member(H1, T1), adj_dups(T1,T3).
This gives R=[a,b] for the input [a,b,b,a], and R=[a,c] for your example input [a,b,a,a,a,c,c].
Related
Problem: I need to transform this list: [[1,2],[3,4],[5,6]] to [1,3,5], by taking only first items from each sub-list in first list and creating new list with all of them. Language is SWI-Prolog.
My solution: To do this, I wrote this code:
getFirstItems([], Result).
getFirstItems([H|T], Result) :-
[H2|T2] = H,
append(Result,H2,Result2),
getFirstItems(T, Result2).
Issue: But this fails to infinite recursion when tail always equals to [[5,6]]
Question: how to solve this issue and solve this problem correctly?
You are complicating things too much. You need to reason with a declarative mindset, and thus implement what the relationships between the list of lists and the list of first elements are.
Here is a solution:
first_items([], []).
first_items([[H|_]|T], [H|T2]) :-
first_items(T, T2).
Indeed, the only two things we need to state to describe that relationship are:
If the list of lists is empty, then so is the list of first elements.
a first element H is in the list of first elements, followed by the first elements (T2) of the rest of the list of lists (T).
Example queries:
?- first_items([[1,2],[3,4],[5,6]], Z).
Z = [1, 3, 5].
?- first_items(L, [1,3,4]).
L = [[1|_22058], [3|_22070], [4|_22082]].
?- first_items(L, Z).
L = Z, Z = [] ;
L = [[_22048|_22050]],
Z = [_22048] ;
L = [[_22048|_22050], [_22066|_22068]],
Z = [_22048, _22066]
…
I want to find the bigger value from a list's element's pairs.
Ie. list=[5,7,4,5,6,8] the pairs are [5,7], [7,4], [4,5] etc.
Right now I have this little code snippet:
bigger([],X).
bigger([E1],[H|E1]).
bigger([E1,E2|T],[H|_]):-
(E1>E2,bigger([E2|T],[H|E1]));
(E1<E2,bigger([E2|T],[H|E2])).
The solution should look like:
?- bigger([5,7,4,5,6,8],X).
X = [7,7,5,6,8,8]
EDIT:
Deleted the remove/3 lines, since they're wrong.
I'll give MY understanding of how the code works.
Empty given list check.
One element list check, adds it to output list end ([H|E1])
More than one element in given list, output list
3.1 First two element check (E1 >/< E2)
3.2 New recursive query without E1 (first element)
3.3 Whichever is bigger is output list's last element now.
First I'll show you my solution of your problem (and the result shouldn't be X = [7,7,5,6,8]? I'll make this version.)
gtr(X,Y,Y) :-
Y>=X.
gtr(X,_,X).
bigger([],[]).
bigger([_], []).
bigger([X,Y|R], [Z|H]) :-
bigger([Y|R],H), gtr(X,Y,Z),!.
If you want to have last element appear in this list anyway than just change second bigger function.
Since the relation is describing lists you could opt to use DCGs for the task:
max_of(X,X,Y) :- X >= Y. % X is maximum if X>=Y
max_of(Y,X,Y) :- Y > X. % Y is maximum if Y>X
list_biggers(L,B) :-
phrase(biggers(L),B). % the DCG biggers//1 describes B based on L
biggers([]) --> % if the list is empty
[]. % there's no element in the biggers list
biggers([X]) --> % if the list contains just one element
[X]. % it is in the biggers list
biggers([X,Y|Xs]) --> % if the list contains at least two elements
{max_of(M,X,Y)}, % the maximum of them
[M], % is in the biggers list
biggers([Y|Xs]). % the same holds for [Y|Xs]
This definition is sticking to your reading of the task, that is, in the case of a one-element list the only element is in the list of bigger elements:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8, 8] ;
false.
?- list_biggers([1],B).
B = [1] ;
false.
If you prefer the reading suggested by #Armatorix, just change the second DCG-rule to
biggers([_X]) -->
[].
This way the queries above yields the following results:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8] ;
false.
?- list_biggers([1],B).
B = [] ;
false.
Note that the list has to be sufficiently instantiated. Otherwise you get an error:
?- list_biggers([X,Y,Z],B).
ERROR: >=/2: Arguments are not sufficiently instantiated
If the list only contains integers, you can remedy this problem by using CLP(FD). Add a line to include the library and change max_of/2 like so:
:- use_module(library(clpfd)).
max_of(X,X,Y) :- X #>= Y.
max_of(Y,X,Y) :- Y #> X.
Now the query above delivers all 4 expected solutions:
?- list_biggers([X,Y,Z],B).
B = [X, Y, Z],
X#>=Y,
Y#>=Z ;
B = [X, Z, Z],
X#>=Y,
Y#=<Z+ -1 ;
B = [Y, Y, Z],
X#=<Y+ -1,
Y#>=Z ;
B = [Y, Z, Z],
X#=<Y+ -1,
Y#=<Z+ -1 ;
false.
In order to construct logical programs, one needs to think logical. Based on the problem statement, there are three possibilities here:
we have an empty list, in that case the result is an empty list as well:
bigger([],[]).
in case we have a list with one element, the problem is underspecified. I would say that the result should be an empty list, but your example seems to suggest that we return that number, since we then have a 1-tuple, and the maximum of a 1-tuple is of course the single element in the tuple:
bigger([H],[H]).
in case the list contains two or more elements [H1,H2|T], then H1 and H2 are the first two elements. In that case we construct a vitual tuple in our head [H1,H2] and calculate the maximum, which is thus M is max(H1,H2). We prepend M to the resulting list of the recursion. That recursion is done on the list [H2|T]: the list where we popped H1 from:
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger([H2|T],U).
Or putting this all together:
bigger([],[]).
bigger([H],[H]).
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger(T,U).
I am trying to get my head wrap around lists in Prolog. To do this I am trying to create a sort of game. You pass in a list of numbers 1-9 that can be repeated, the list can be any length. The rules are that starting from the first element(e) you can only move to e+2 or e+3 until you get to the end. The goal is to "land" on the highest numbers. In essence it is kind of like hopscotch. The problem I am running into is determining all the possible permutation for paths. So far I have the following.
paths([], []). %empty list returns empty list
paths([X], [X]). %list with one element returns that one element
paths([X1, X2], [X1]). %list with 2 elements returns the first element
paths([X1, X2, X3], [X1,X3]). %list with three elements returns the first and third element
paths() :- % the recursive case for a list with 4+ elements
An list to use would be: [1,2,3,4,5,6,8,7,9,3,6,5,7,8,9]
I need to determine all possible paths using the rule mentioned about. I wish lists could be indexed in Prolog :(
Any logic guidance would be appreciated.
The requirements aren't completely clear, but it seems that:
The second argument is required to have the same first element as the
first argument (you "hop" on the first "square" first always, using
your hopscotch metaphore)
You aren't requiring that the last element of the first list be the
last element of the second list (you aren't requiring that you "land
on" the last "square").
An empty list succeeds with an empty list result (rather than just failing on an empty list - which is another valid approach).
Then this could be implemented as follows. You do not need many explicit 2- and 3-element list cases since they are handled by the recursive clause and simpler base cases.
path([], []).
path([X], [X]).
path([X,_|T], [X|R]) :- % hop over 1 element
path(T, R).
path([X,_,_|T], [X|R]) :- % hop over 2 elements
path(T, R).
For a simple example:
| ?- path([1,2,3,4,5,6], R).
R = [1,3,5] ? ;
R = [1,3,6] ? ;
R = [1,4,6] ? ;
R = [1,4]
yes
If I don't have your requirements exactly right, you should be able to adjust this to suit your needs as it shows how to handle a recursive case. It also sounds like you are headed in the direction of trying to optimize the values in your hops, which I shall also leave as an exercise.
This can also be done with a DCG (definite clause grammar)
path([]) --> [].
path([X]) --> [X].
path([X|T]) --> ([X,_] | [X,_,_]), path(T).
Which would be exercised:
| ?- phrase(path(R), [1,2,3,4,5,6]).
R = [1,3,5] ? ;
R = [1,3,6] ? ;
R = [1,4,6] ? ;
R = [1,4] ? ;
(1 ms) no
| ?-
In light of the extra requirement that the last step taken must be one that falls within the list, here is an updated version of the path/2 predicate:
path([], []).
path([X], [X]).
path([X,_], [X]).
path([X,_,Y|T], [X|R]) :- % hop over 1 element
path([Y|T], R).
path([X,_,_,Y|T], [X|R]) :- % hop over 2 elements
path([Y|T], R).
I think that there is a reason to avoid indexing: simplicity. If you decompose your problem, maybe you could start writing a step/3 predicate like
step([_,X|T],X,T).
step([_,_,X|T],X,T).
and then
paths([],[]).
paths(L,[X|Xs]) :- step(L,X,T), paths(T,Xs).
note: I don't understand very well your game, some example of playground and solution would be welcome.
%passing in a list and return all possible paths using K+2 or K+3 with K being the first element of the list.
%empty list returns empty list
%list with one element returns that one element
%list with 2 elements returns the first element
%list with three elements returns the first and third element
%list with four/four+ elements needs to be called recursively, prefix them with the first element and append them together
%RL means ReturnList
%FL means FinalList
%List is the appended list containing all the paths
paths([], []).
paths([X], [[X]]).
paths([X1, X2], [[X1]]).
paths([X1, X2, X3], [[X1,X3]]).
paths([X1, X2, X3, X4 | T], List) :-
paths([X3,X4|T], RL), paths([X4|T], RL2),
prefix_all(X1, RL, FL1), prefix_all(X1, RL2, FL2),
append(FL1, FL2, List).
So if run with the list [1,2,3,4,5] is would produce the following:
| ?- paths([1,2,3,4,5],X).
X = [[1,3,5],[1,4]] ? ;
no
Again a Prolog beginner :-}
I build up a list element by element using
(1)
member(NewElement,ListToBeFilled).
in a repeating call,
(2)
ListToBeFilled = [NewElement|TmpListToBeFilled].
in a recursive call like
something(...,TmpListToBeFilled).
A concrete example of (2)
catch_all_nth1(List, AllNth, Counter, Result) :-
[H|T] = List,
NewCounter is Counter + 1,
(
0 is Counter mod AllNth
->
Result = [H|Result1]
;
Result = Result1
),
catch_all_nth1(T,AllNth,NewCounter,Result1),
!.
catch_all_nth1([], _, _, _).
As result I get a list which looks like
[E1, E2, E3, ..., Elast | _G12321].
Of course, the Tail is a Variable. [btw: are there better method to fill up the
list, directly avoiding the "unassigned tail"?]
I was now looking for a simple method to eliminate the "unassigned tail".
I found:
Delete an unassigned member in list
there it is proposed to use:
exclude(var, ListWithVar, ListWithoutVar),!,
[Found this too, but did not help as I do not want a dummy element at the end
Prolog list has uninstantiated tail, need to get rid of it ]
What I noticed is that using length\2 eliminate the "unassigned tail", too, and in addtion
the same List remains.
My Question is: How does it work? I would like to use the mechanism to eliminate the unassigned tail without using a new variable... [in SWI Prolog 'till now I did not get the debugger
entering length() ?!]
The example:
Z=['a','b','c' | Y],
X = Z,
write(' X '),write(X),nl,
length(X,Tmp),
write(' X '),write(X),nl.
13 ?- test(X).
X [a,b,c|_G3453]
X [a,b,c]
X = [a, b, c] .
I thought X, once initialized can not be changed anymore and you need
a new variable like in exclude(var, ListWithVar, ListWithoutVar).
Would be happy if someone explain the trick to me...
Thanks :-)
You're right about the strange behaviour: it's due to the ability of length/2 when called with unbound arguments
The predicate is non-deterministic, producing lists of increasing length if List is a partial list and Int is unbound.
example:
?- length([a,b,c|X],N).
X = [],
N = 3 ;
X = [_G16],
N = 4 ;
X = [_G16, _G19],
N = 5 ;
...
For your 'applicative' code, this tiny correction should be sufficient. Change the base recursion clause to
catch_all_nth1([], _, _, []).
here are the results before
4 ?- catch_all_nth1([a,b,c,d],2,1,R).
R = [b, d|_G75].
and after the correction:
5 ?- catch_all_nth1([a,b,c,d],2,1,R).
R = [b, d].
But I would suggest instead to use some of better know methods that Prolog provide us: like findall/3:
?- findall(E, (nth1(I,[a,b,c,d],E), I mod 2 =:= 0), L).
L = [b, d].
I think this should do it:
% case 1: end of list reached, replace final var with empty list
close_open_list(Uninstantiated_Var) :-
var(Uninstantiated_Var), !,
Uninstantiated_Var = '[]'.
% case 2: not the end, recurse
close_open_list([_|Tail]) :-
close_open_list(Tail).
?- X=[1,2,3|_], close_open_list(X).
X = [1, 2, 3].
Note that only variable X is used.. it simply recurses through the list until it hits the var at the end, replaces it with an empty list, which closes it. X is then available as a regular 'closed' list.
Edit: once a list element has been assigned to something specific, it cannot be changed. But the list itself can be appended to, when constructed as an open list ie. with |_ at the end. Open lists are a great way to build up list elements without needing new variables. eg.
X=[1,2,3|_], memberchk(4, X), memberchk(5,X).
X = [1, 2, 3, 4, 5|_G378304]
In the example above, memberchk tries tries to make '4', then '5' members of the list, which it succeeds in doing by inserting them into the free variable at the end in each case.
Then when you're done, just close it.
Im new to Prolog and was looking for some assistance. What i am trying to do is basically get a list L consisting of elements that repeat at least twice in a given list L'
Example
L'=[1,2,1,3,4,3,2] => L=[1,2,3].
So far I am able to compute the occurrence of every consecutive variables
% pack(L1,L2) :- the list L2 is obtained from the list L1 by packing
% repeated occurrences of elements into separate sublists.
% (list,list) (+,?)
pack([],[]).
pack([X|Xs],[Z|Zs]) :- transfer(X,Xs,Ys,Z), pack(Ys,Zs).
% transfer(X,Xs,Ys,Z) Ys is the list that remains from the list Xs
% when all leading copies of X are removed and transfered to Z
transfer(X,[],[],[X]).
transfer(X,[Y|Ys],[Y|Ys],[X]) :- X \= Y.
transfer(X,[X|Xs],Ys,[X|Zs]) :- transfer(X,Xs,Ys,Zs).
% encode(L1,L2) :- the list L2 is obtained from the list L1 by run-length
% encoding. Consecutive duplicates of elements are encoded as terms [N,E],
% where N is the number of duplicates of the element E.
% (list,list) (+,?)
encode(L1,L2) :- pack(L1,L), transform(L,L2).
transform([],[]).
transform([[X|Xs]|Ys],[[N,X]|Zs]) :- length([X|Xs],N), transform(Ys,Zs).
which will return the following list of touples
?- encode([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
X = [[4,a],[1,b],[2,c],[2,a],[1,d][4,e]]
But there still remains the problem of building a list that will contain distinct elements that repeat at least twice.
If anyone can help me or point me in the general direction that would be great.
Thanks in advance
an element E of list L should:
be a member of list L',
be a member of list L'' where L'' is list L' if we remove element E.
check select/3, member/2, findall/3 and/or setof/3
You could write a procedure:
% E it's the list of are elements from L that repeat at least twice
elements_that_repeat_at_least_twice(L, E) :-
elements_that_repeat_at_least_twice(L, [], E).
elements_that_repeat_at_least_twice([H|Ls], Dupl, E) :-
...
In elements_that_repeat_at_least_twice the added list Dupl will keep each element you verify it's present multiple times. Examine each element of L, using [H|Ls].
Use memberchk/2 to verify if H is in L: then it's at least duplicate. If it's not yet in Dupl, add to it, and recurse. Remember to write the recursion base case (stop at empty list []).
Now I see you have added some code: then I complete suggestion:
elements_that_repeat_at_least_twice([], Dupl, Dupl).
elements_that_repeat_at_least_twice([H|Ls], Dupl, E) :-
( memberchk(H, Ls)
-> ( \+ memberchk(H, Dupl)
-> Dupl1 = [H|Dupl]
; Dupl1 = Dupl
)
; Dupl1 = Dupl
),
elements_that_repeat_at_least_twice(Ls, Dupl1, E).
Remember to reverse the list of duplicates when done.