Related
i should write a rule on prolog, which finds the last element of a list and add 1 to it. Here's what i came up with so far. It works, but my question is can this rule be written otherwise:
element(D ,[_|B]):- element(D, B).
element(D, [X]):- D is X+1.
(1) I'd rename the predicate to something like last_element_incremented which would be more descriptive than just element which doesn't say much.
(2) To make the rules non-overlapping, change the recursive rule:
last_element_incremented(Xinc, [_,X|T]) :- last_element_incremented(Xinc, [X|T]).
(3) If you use CLP(FD) you can make the solution more general. Also, swap the order of clauses so that you don't get a non-termination issue for more general queries:
last_element_incremented(Xinc, [X]) :- Xinc #= X + 1.
last_element_incremented(Xinc, [_,X|T]) :- last_element_incremented(D, [X|T]).
Then you can query, for example:
| ?- last_element_incremented(3, L).
L = [2] ? ;
L = [_,2] ? ;
L = [_,_,2] ? ;
L = [_,_,_,2] ? ;
(4) Finally, you could just use append/3:
last_element_incremented(Xinc, L) :- append(_, [X], L), Xinc #= X + 1.
I want to make a program that given a list L in which element X appears 3 times, it returns the NL list including it only one time.
For example, this question
?- erase([1,2,3,1,6,1,7],1,NL).
should return
NL = [1,2,3,6,7] or NL = [2,3,1,6,7] or NL = [2,3,6,1,7]
P.S.
Suppose that the given list doesn't include any element 2,4 or more times.
So, this is my code, but it returns false when I make a question. Any suggestion to correct it would be appreciated.
erase([],_,[]).
erase(L,X,NL):-
append(A,[X,B,X,C,X,D],L),
append(A,[X,B,C,D],NL).
So you say, that the following query should succeed, but fails
?- erase([1,2,3,1,6,1,7],1,NL).
false.
even the following generalization fails:
?- erase([1,2,3,1,6,1,7],E,NL).
false.
Let me reformulate this for easier access:
?- L = [1,2,3,1,6,1,7], erase(L,E,NL).
false.
So we now have to generalize that list even further. I could try this element by element, but I rather prefer first:
?- L = [_,_,_,_,_,_,_], erase(L,E,NL).
L = [_A,E,_B,E,_C,E,_D], NL = [_A,E,_B,_C,_D]
; false.
This is the only answer. It tells us that E has to occur exactly at the 2nd, 3rd and 5th position. Let's try if that is true:
?- erase([0,1,0,1,0,1,0],1,NL).
NL = [0,1,0,0,0]
; false.
So your solution works — sometimes. It seems that you rather want:
erase(L, X, NL) :-
phrase(
( seq(Any1), [X], seq(Any2), [X], seq(Any3), [X], seq(Any4) ), L),
phrase(
( seq(Any1), seq(Any2), seq(Any3), [X], seq(Any4) ), NL).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
append/2 helps a lot when processing multiple lists:
erase(L,E,R) :-
append([A,[E],B,[E],C,[E],D],L),
select([E],[X,Y,Z],[[],[]]),
append([A, X, B, Y, C, Z, D],R).
I have list like following :
[a,b,b,e,e,f,f,g]
The first and last entries are single, while all others are repeated. How can I remove these extra entries. I should not disturb the order.
I tried following but it gets an empty list:
removeDups([], []).
removeDups([H1,H2|T], Newlist) :-
(H1 == H2 -> removeDups([H2|T],Newlist)
; removeDups(T,Newlist)).
?- removeDups([a,b,b,c,c,d,d,e],L).
L = [].
Edit: I have already checked many similar question on stackoverflow. But in my list the duplicates are consecutive and therefore a simpler solution may be possible. I could not find a question on removing consecutive duplicate entries.
Why resort to solutions that can only be used in very specific cases, and yield wrong results in other cases? Imperative programming is so 1980... The 80s were cool, I know, but a bit limited too, no?
Try thinking in terms of relations that can be used in all directions!
Here is a solution that uses if_/3 for generality:
no_consecutive_duplicates([], []).
no_consecutive_duplicates([L|Ls0], Ls) :-
no_dups(Ls0, L, Ls).
no_dups([], E, [E]).
no_dups([L|Ls0], E, Ls) :-
if_(L=E, Ls=Ls1, Ls=[E|Ls1]),
no_dups(Ls0, L, Ls1).
It works also in the most general case:
?- no_consecutive_duplicates(Ls0, Ls).
Ls = Ls0, Ls0 = []
Ls = Ls0, Ls0 = [_G501] ;
Ls = [_G501],
Ls0 = [_G501, _G501] ;
Ls = [_G501],
Ls0 = [_G501, _G501, _G501] .
For fair enumeration, use for example:
?- length(Ls0, _), no_consecutive_duplicates(Ls0, Ls).
Ls = Ls0, Ls0 = [] ;
Ls = Ls0, Ls0 = [_G501] ;
Ls = [_G501],
Ls0 = [_G501, _G501] ;
Ls = [_G775, _G775],
Ls0 = [_G787, _G775],
dif(_G775, _G787) .
Note the use of prolog-dif to declaratively state that two terms are different.
And by the way, "normal" cases work too:
?- no_consecutive_duplicates([a,b,c], Ls).
Ls = [a,b,c].
?- no_consecutive_duplicates([a,a,b,c,c], Ls).
Ls = [a,b,c].
Note that both queries succeed deterministically.
And isn't it nice that we can generalize this and inspect also slightly more complex cases?
?- no_consecutive_duplicates([a,b,X], Ls).
Ls = [a, b],
X = b ;
Ls = [a, b, X],
dif(X, b).
Stay pure folks!
In your predicate, the second argument should always represent the result of duplicates being removed from the first argument. That leads to the following clauses when broken down into each case:
remove_dups([], []). % Empty list is empty list with dups removed
remove_dups([X], [X]). % Single element list is itself with dups removed
% The result of removing duplicates from `[X,X|T]` should be the same
% as the result of removing duplicates from `[X|T]`
remove_dups([X,X|T], [X|R]) :-
remove_dups([X|T], [X|R]).
% The result of removing duplicates from `[X,Y|T]` where X and Y are different
% should be the result [X|R] where R is the result of removing duplicates
% from [Y|T]
remove_dups([X,Y|T], [X|R]) :-
X \== Y,
remove_dups([Y|T], R).
The 3rd and 4th clauses could be replaced with:
remove_dups([X,Y|T], [X|R]) :-
( X == Y
-> remove_dups([Y|T], [X|R])
; remove_dups([Y|T], R)
).
But then it will limit solutions where the first argument is variable.
An empty list with its duplicates removed is, of course, still an empty list.
If the tail does not start with the head, we should keep the head. The de-duplicated tail is the tail with its duplicates removed.
This includes the case where the tail is empty (and so it is a single-element list).
If the list does start with its head repeated, we keep the head. Then we include the head when removing the other duplicates, since the head may be repeated more than once. If we don't include the head, we can't check the tail against it.
remove_dups([],[]).
remove_dups([H|T], [H|T1]) :-
T \= [H|_],
remove_dups(T, T1).
remove_dups([H,H|T], L) :-
remove_dups([H|T], L).
And here's an example using SWISh.
The simplest way in which you can do this is by using takeout function and member function
takeout(X,[X|R],R).
takeout(X,[F|Fs],[F|S]):- takeout(X,Fs,S).
/*takeout function used to remove
delete given element from the list*/
rem([X],[X]).
rem([H|T],Z):- member(H,T) , takeout(H,[H|T],L) ,!, rem(L,Z).
rem([H|T],[H|Z]):- \+member(H,T) , rem(T,Z).
/* I used cut to stop backtracking of takeout function
rem([X],[X]). when only one elem present return the same list
rem([H|T],Z):-member(H,T) , takeout(H,[H|T],L) ,!, rem(L,Z).
used to takeout the duplicate element from the list.
rem([H|T],[H|Z]):- \+member(H,T) , rem(T,Z).
if Head is not present in the tail , do nothing and check for the same in tail.
*/
Given a list eg [1,2,3,7,2,5,8,9,3,4] how would I extract the sequences within the list?
A sequence is defined as an ordered list (Normally I would say n-tuple but I have been told in prolog a tuple is referred to as a sequence). So we want to cut the list at the point where the next element is smaller than the previous one.
So for the list [1,2,3,7,2,5,8,9,3,4] it should return:
[ [1,2,3,7], [2,5,8,9], [3,4] ] %ie we have cut the list at position 4 & 8.
For this exercise you CANNOT use the construct ; or ->
Many thanks in advance!
EXAMPLE RESULTS:
eg1.
?-function([1,2,3,7,2,5,8,9,3,4],X): %so we cut the list at position 4 & 9
X = [ [1,2,3,7], [2,5,8,9], [3,4] ].
eg2.
?-function([1,2,3,2,2,3,4,3],X): %so we cut the list at position 3,4 & 8
X = [ [1,2,3], [2], [2,3,4], [3] ].
Hopefully that helps clarify the problem. If you need further clarification just let me know! Thanks again in advance for any help you are able to provide.
First, let's break it down conceptually. The predicate list_ascending_rest/3 defines a relation between a list Xs, the left-most ascending sublist of maximum length Ys, and the remaining items Rest. We will use it like in the following query:
?- Xs = [1,2,3,7,2,5,8,9,3,4], list_ascending_rest(Xs,Ys,Rest).
Ys = [1,2,3,7],
Rest = [2,5,8,9,3,4] ;
false.
The straight-forward predicate definition goes like this:
:- use_module(library(clpfd)).
list_ascending_rest([],[],[]).
list_ascending_rest([A],[A],[]).
list_ascending_rest([A1,A2|As], [A1], [A2|As]) :-
A1 #>= A2.
list_ascending_rest([A1,A2|As], [A1|Bs], Cs) :-
A1 #< A2,
list_ascending_rest([A2|As], Bs,Cs).
Then, let's implement predicate list_ascendingParts/2. This predicate repeatedly uses list_ascending_rest/3 for each part until nothing is left.
list_ascendingParts([],[]).
list_ascendingParts([A|As],[Bs|Bss]) :-
list_ascending_rest([A|As],Bs,As0),
list_ascendingParts(As0,Bss).
Example queries:
?- list_ascendingParts([1,2,3,7,2,5,8,9,3,4],Xs).
Xs = [[1,2,3,7], [2,5,8,9], [3,4]] ;
false.
?- list_ascendingParts([1,2,3,2,2,3,4,3],Xs).
Xs = [[1,2,3], [2], [2,3,4], [3]] ;
false.
Edit 2015/04/05
What if the ascending parts are known but the list is unknown? Let's find out:
?- list_ascendingParts(Ls, [[3,4,5],[4],[2,7],[5,6],[6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ? ;
no
And let's not forget about the most general query using list_ascendingParts/2:
?- assert(clpfd:full_answer).
yes
?- list_ascendingParts(Ls, Ps).
Ls = [], Ps = [] ? ;
Ls = [_A], Ps = [[_A]] ? ;
Ls = [_A,_B], Ps = [[_A],[_B]], _B#=<_A, _B in inf..sup, _A in inf..sup ? ...
Edit 2015-04-27
Room for improvement? Yes, definitely!
By using the meta-predicate splitlistIfAdj/3 one can "succeed deterministically" and "use non-determinism when required", depending on the situation.
splitlistIfAdj/3 is based on if_/3 as proposed by #false in this answer. So the predicate passed to it has to obey the same convention as (=)/3 and memberd_truth/3.
So let's define (#>)/3 and (#>=)/3:
#>=(X,Y,Truth) :- X #>= Y #<==> B, =(B,1,Truth).
#>( X,Y,Truth) :- X #> Y #<==> B, =(B,1,Truth).
Let's re-ask above queries, using splitlistIfAdj(#>=)
instead of list_ascendingParts:
?- splitlistIfAdj(#>=,[1,2,3,7,2,5,8,9,3,4],Pss).
Pss = [[1,2,3,7],[2,5,8,9],[3,4]]. % succeeds deterministically
?- splitlistIfAdj(#>=,[1,2,3,2,2,3,4,3],Pss).
Pss = [[1,2,3],[2],[2,3,4],[3]]. % succeeds deterministically
?- splitlistIfAdj(#>=,Ls,[[3,4,5],[4],[2,7],[5,6],[6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ; % works the other way round, too
false. % universally terminates
Last, the most general query. I wonder what the answers look like:
?- splitlistIfAdj(#>=,Ls,Pss).
Ls = Pss, Pss = [] ;
Ls = [_G28], Pss = [[_G28]] ;
Ls = [_G84,_G87], Pss = [[_G84],[_G87]], _G84#>=_G87 ;
Ls = [_G45,_G48,_G41], Pss = [[_G45],[_G48],[_G41]], _G45#>=_G48, _G48#>=_G41
% and so on...
maplist/3 as suggested in the comment won't help you here because maplist/3 is good at taking a list and mapping each element into a same-size collection of something else, or establishing a relation evenly across all of the individual elements. In this problem, you are trying to gather contiguous sublists that have certain properties.
Here's a DCG solution. The idea here is to examine the list as a series of increasing sequences where, at the boundary between them, the last element of the prior sequence is less than or equal to the first element of the following sequence (as the problem statement basically indicates).
% A set of sequences is an increasing sequence ending in X
% followed by a set of sequences that starts with a value =< X
sequences([S|[[Y|T]|L]]) --> inc_seq(S, X), sequences([[Y|T]|L]), { X >= Y }.
sequences([S]) --> inc_seq(S, _).
sequences([]) --> [].
% An increasing sequence, where M is the maximum value
inc_seq([X,Y|T], M) --> [X], inc_seq([Y|T], M), { X < Y }.
inc_seq([X], X) --> [X].
partition(L, R) :- phrase(sequences(R), L).
| ?- partition([1,2,3,4,2,3,8,7], R).
R = [[1,2,3,4],[2,3,8],[7]] ? ;
(1 ms) no
| ?- partition([1,2,3,2,2,3,4,3],X).
X = [[1,2,3],[2],[2,3,4],[3]] ? ;
(1 ms) no
The only reason for the rule sequences([]) --> []. is if you want partition([], []) to be true. Otherwise, the rule isn't required.
I need to know how can i get all of combination of appending two lists with each other without repetition like [1,2] & [3,4] the result will be [1,3] [1,4] [2,3] [2,4]
This is the solution that does not work as desired:
(1) comb([], [], []).
(2) comb([H|T], [X|Y], [H,X]).
(3) comb([H,T|T1], [X,Y|T2], [T,Y]).
(4) comb([H|T], [X|Y], L) :-
comb(T, Y, [H|X]).
(1) says, Combining an empty list with an empty list is an empty list. This sounds logically correct.
(2) says, [H,X] is a pair of elements from [H|T] and [X|Y]. This is true (provides only one of the combinations for the solution).
(3) says, [T,Y] is a pair of elements from [H,T|T1] and [X,Y|T2]. This is also true (provides only one other combination for the solution, different to #2).
(4) says, L is a pair of elements from [H|T] and [X|Y] if [H|X] is a pair of elements from T and Y. This can't be true since L doesn't appear in the consequent of the clause, so it will never be instantiated with a value.
The above solution is over-thought and more complicated than it needs to be. It fails because it hard-codes two solutions (matching the first two elements and the second two elements). The recursive clause is then faulty since it doesn't have a logical basis, and the solution is left as a singleton variable.
To start, you need to decide what your predicate means. In this particular problem, you can think of your predicate comb(Xs, Ys, P). as being TRUE if P is a pair (say it's [X,Y]) where X is from Xs (i.e., X is a member of Xs) and Y is from Ys (Y is a member of Ys). Then, when you query your predicate, it will prompt you with each solution until all of them have been found.
This problem can be stated with one rule: [X,Y] is a combination of elements taken from Xs and Ys, respectively, if X is a member of Xs and Y is a member of Ys. That sounds like a trivially true statement, but it's all you need to solve this problem.
Translating this into Prolog gives this:
comb(Xs, Ys, [X,Y]) :- % [X,Y] is combination of elements from Xs and Ys if...
member(X, Xs), % X is a member of Xs, and
member(Y, Ys). % Y is a member of Ys
Now let's try it:
| ?- comb([1,2],[3,4],P).
P = [1,3] ? ;
P = [1,4] ? ;
P = [2,3] ? ;
P = [2,4]
(2 ms) yes
| ?-
It found all of the combinations. We let Prolog do all the work and we only had to declare what the rule was.
If you want to collect all the results in a single list, you can use a built-in predicate such as findall/3:
| ?- findall(P, comb([1,2], [3,4], P), AllP).
AllP = [[1,3],[1,4],[2,3],[2,4]]
yes
| ?-
And voilà. :)
You can also generalize the solution very easily and choose one element each from each list in a given list of lists. Here, multicomb/2 has as a first argument a list of lists (e.g., [[1,2], [3,4]]` and generates every combination of elements, one from each of these sublists:
multicomb([L|Ls], [X|Xs]) :-
member(X, L),
multicomb(Ls, Xs).
multicomb([], []).
Which gives:
| ?- multicomb([[1,2],[3,4]], P).
P = [1,3] ? a
P = [1,4]
P = [2,3]
P = [2,4]
yes
| ?-
And:
| ?- multicomb([[1,2],[a,b],[x,y,z]], P).
P = [1,a,x] ? a
P = [1,a,y]
P = [1,a,z]
P = [1,b,x]
P = [1,b,y]
P = [1,b,z]
...