Add non repeating elements to List in Prolog - list

I have a List and I am trying to add to it elements from another list that are not already present in the first List.
So if I had 2 Lists :
[a, b, 3, c]
[2, a, b, 4]
The output would be:
[a, b, 3, c, 2, 4]
I am able to get it in reversed order but not in the correct one, here is what I am trying to do:
add_to_list(L, [], L).
add_to_list(List, [H|T], [H|Res]) :-
\+ member(H, List),
add_to_list(List, T, Res).
add_to_list(List, [H|T], Res):-
add_to_list(List, T, Res).
And when I do the method with the 2 Lists mentioned above the output I get is:
[2, 4, a, b, 3, c]
I am aware that my ending clause is adding the L to the end of the result I get, which is why the order is a mess but how can I do it the correct way?

Well the problem here is that you should first move to the end of the first list before concatenating data.
We can still use the code you have written, but alter it slightly like:
atl(_, [], []).
atl(List, [H|T], R) :-
( member(H, List)
-> R = Res
; R = [H|Res]
),
atl(List, T, Res).
We here basically made three changes: (a) we renamed addToList/3 to atl/3; we changed L to [] in the first line; and (c) we used an if-then-else to prevent that the third clause gets triggered even if H is not a member of List (this was a semantical error in your code).
Now we will obtain for the given input as output:
?- atl([a, b, 3, c] , [2, a, b, 4], R).
R = [2, 4] ;
false.
So now we can write an addToList/3 in terms of atl/3: we first generate the list of items to append, and next we use append/3 to append these at the end of the list:
addToList(A, B, L) :-
atl(A, B, R),
append(A, R, L).

Related

Prolog creating lists

I'm trying to write a program in Prolog that will take in three lists (all of which are the same length) and return a list of lists.
The list of lists that I am returning is a triple that contains elements from the three lists that are being passed in. The first element of the triple is from the first list passed in, the second element of the triple is from the second list, and the third element of the triple is from the third list passed in.
What I want to have happen is the list of triples that the function is returning to return every single possible combination that you could make from the three lists being passed in.
As of now I have some code that takes the first elements of the three lists and makes a triple out of them, then takes the second element of all the lists and makes a triple out of them, and so on. Here it is below.
listCombos( [], [], [], []).
listCombos( [A|AREST], [B|BREST], [C|CREST], [[A,B,C]|SOLUTION]) :-
listCombos( AREST, BREST, CREST, SOLUTION).
My strategy for getting every combo is taking the first element of the first list and the first element in the second list and then going through each elements in the third list. Once I have done that I will move on the the first element in the first list and the second element in the second list and match those up with each element in the third list. Then after I have went through the second list move onto the first list. Let me know if more clarification on this is needed.
I'm new to Prolog so I don't understand how to turn what I'm planning to do into code. I've tried a few things but haven't been successful and have gotten some error codes I don't understand so it's hard to tell if I'm going in the right direction (I can post some of my attempts if needed). If anyone has some idea of what direction I should go in or some explanation on what I need to do that would be appreciated.
Thank you very much.
Knowing a little Prolog the most obvious solution is something like this:
listCombos(Xs, Ys, Zs, Result) :-
findall([X,Y,Z],
(member(X, Xs), member(Y, Ys), member(Z, Zs)),
Result).
It's advisable to generalize the construct you're looking for, accepting a list of lists to be combined, following the schema from this answer:
combine(Ls,Rs) :- maplist(member,Rs,Ls).
listCombos(A,B,C, SOLUTION) :- findall(R,combine([A,B,C],R),SOLUTION).
We first can solve a related problem: given a list of "heads" Hs and a list of "tails" Ts, construct all lists for all heads H in Hs, and all tails T in Ts in a list. We can do this with a predicate:
merge_all([], _, []).
merge_all([H|Hs], Ts, All) :-
merge_single(Ts, H, All, D),
merge_all(Hs, Ts, D).
merge_single([], _, D, D).
merge_single([T|Ts], H, [[H|T]|Rest], D) :-
merge_single(Ts, H, Rest, D).
For example:
?- merge_all([a, b], [[1, 4], [2, 5]], R).
R = [[a, 1, 4], [a, 2, 5], [b, 1, 4], [b, 2, 5]].
Now we can use this for example to make all cross products with Cs and the "empty set", for example if Cs = [a, b, c], then:
?- merge_all([a, b, c], [[]], RC).
RC = [[a], [b], [c]].
Given we have this result, we can make the cross product of Bs with this result. For example if Bs = [1, 4], then we obtain:
?- merge_all([a, b, c], [[]], RC), merge_all([1, 4], RC, RB).
RC = [[a], [b], [c]],
RB = [[1, a], [1, b], [1, c], [4, a], [4, b], [4, c]].
With the above generating the cross product of three sets should be straightforward, I leave this as an exercise.
The approach by Daniel Lyons is good in that it allows us to easily control the order of combinations in the cross-product of a list of lists, while keeping the order of elements in the combinations the same, of course:
cross( [], [[]] ).
cross( [XS | T], R ):-
cross( T, TC),
findall( [X | Y], ( % or:
member( Y, TC), % member( X, XS)
member( X, XS) % member( Y, TC),
),
R).
It exhibits good modularity and separation of concerns: the order of presentation is independent of the order of generation and the order of selection.

how to make a list of lists with a certain width

i want to implement a function that make a list of sublists with a certain width. For example :
?- list_to_llists([w,w,w,w],2,LL). %1
LL = [[w, w], [w, w]] ;
false.
?- list_to_llists([w,w,c,l,r,w,c,c,w,w,w,w],3,LL). %2
LL = [[w, w, c], [l, r, w], [c, c, w], [w, w, w]] ;
false.
?- list_to_llists([w,w,w,w],3,LL). %3
LL = [[w, w, w]] ;
false.
sublist(I1,I2,L,Sub) :-
sublist2(I1,I2,L,[],Sub).
sublist2(I1,I2,L,Sub,Sub):-
length(Sub,N),
N\=0,
I1>I2.
sublist2(I1,I2,L,Sub,Sub2):-
I1<I2,
nth0(I1,L,X),
I3 is I1+1,
append(Sub,[X],Z),
sublist2(I3,I2,L,Z,Sub2).
sublist2(A,B,L,Sub,Sub2):-
B=A,
nth0(A,L,X),
NewA is A+1,
append(Sub,[X],Z),
sublist2(NewA,B,L,Z,Sub2).
list_to_llists(L,W,LLists):-
length(L,X),
X=<W,
LLists=[L].
list_to_llists2([],W,LLists,A):- LLists=A .
list_to_llists2(L,W,LLists,A):-
P is W-1 ,
sublist(0,P,L,Result),
append([Result],A,U),
append(Result,K,L),
list_to_llists2(K,W,LLists,U).
list_to_llists(L,W,F):-
list_to_llists2(L,W,R,[[]]).
but case 2 and 3 don't work at all
secondly, i want to implement a function that takes certain facts and put them in L where L is a list but i have to use list_to_lists to make L kind of list of lists list (it's a map)
for example (test cases):
?- length(L,100),ensure_hints(L, [at(3, 5, c), at(5, 0, w), at(9, 6, c)],10,10).
L = [_G1699, _G1702, _G1705, _G1708, _G1711, w, _G1717, _G1720, _G1723, _G1726,
_G1729, _G1732, _G1735, _G1738, _G1741, _G1744, _G1747, _G1750, _G1753, _G1756,
_G1759, _G1762, _G1765, _G1768, _G1771, _G1774, _G1777, _G1780, _G1783, _G1786,
_G1789, _G1792, _G1795, _G1798, _G1801, _G1804, _G1807, _G1810, _G1813, _G1816,
_G1819, _G1822, _G1825, _G1828, _G1831, _G1834, _G1837, _G1840, _G1843, _G1846,
_G1849, _G1852, _G1855, c, _G1861, _G1864, _G1867, _G1870, _G1873, _G1876,
_G1879,_G1882, _G1885, _G1888, _G1891, _G1894, _G1897, _G1900, _G1903, c,
_G1909, _G1912,_G1915, _G1918, _G1921, _G1924, _G1927, _G1930, _G1933, _G1936,
_G1939, _G1942, _G1945, _G1948, _G1951, _G1954, _G1957, _G1960, _G1963, _G1966,
_G1969,_G1972, _G1975, _G1978, _G1981, _G1984, _G1987, _G1990, _G1993, _G1996];
false
?- length(L,9),ensure_hints(L, [at(1, 2, c), at(0, 1, l)],3,3).
L = [_G1589, _G1592, _G1595, l, _G1601, _G1604, _G1607, c, _G1613] ;
false.
?- length(L,9),ensure_hints(L, [at(1, 2, c), at(0, 5, l)],3,3).
false.
but it doesn't work for me
my code :
ensure_hints(L,Hints,W,H):-
list_to_llists(L,W,C),
Hints=[H|T],
H=at(X,Y,O),
nth0(X,L,Z),
nth0(Y,Z,O),
ensure_hints(L,T,W,H).
Here is a simple solution:
list_to_llists(List, Len, [H|T]) :-
length(H, Len),
append(H, Rest, List),
!,
list_to_llists(Rest, Len, T).
list_to_llists(_, _, []).
It simple removes sublists of length Len until there is no complete sublist left (it seems you want to ignore incomplete sublists).
You can play with it on http://swish.swi-prolog.org/p/OqfzwRoe.pl

minimum in list of lists in prolog

hello i have a list like this:
[[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]]
list of lists...
i want to find the minimum number on inner list
in this case i want to return D=2 and L=[a,b,d]
i tried this code:
minway([[N|L]],N,L).
minway([[M|L1]|L2],D,_):- M<D, minway(L2,M,L1).
minway([[M|_]|L2],D,L):- M>=D, minway(L2,D,L).
but i got error:
</2: Arguments are not sufficiently instantiated
Exception: (8) minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]], _G7777, _G7778) ?
creep
for this run sentence:
minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).
the result need to be:
D=2.
L=[a,b,d].
where my problem?
and how to fix it?
tnx a lot
First, switch to a better data representation: Instead of [Key,Value], use Key-Value!
Then, define minway_/3 based on
iwhen/2,
ground/1,
keysort/2, and
member/2, like so:
minway_(Lss, N, Ls) :-
iwhen(ground(Lss), (keysort(Lss,Ess), Ess = [N-_|_], member(N-Ls, Ess))).
Sample query using SICStus Prolog 4.5.0:
| ?- minway_([3-[a,b,c,d],2-[a,b,d],5-[d,e,f],2-[x,t,y]], N, Ls).
N = 2, Ls = [a,b,d] ? ;
N = 2, Ls = [x,t,y] ? ;
no
There are a couple of fundamental issues.
One is in your problem lies in your representation of a list. Your predicates seem to assume that, for example, [3, [a,b,c]] is represented as [3 | [a,b,c]] but it is not. The list [3 | [a,b,c]] is the list with 3 as the head, and [a,b,c] as the rest of the list or the tail. In other words, [3 | [a,b,c]] is [3, a, b, c].
And, so, your base case would be:
minway([[N,L]], N, L).
The second issue is in your other predicate clauses. There's no starting point for D. In other words, it's never given a value to start with, so you get an instantiation error. You cannot compare N > D if one of the variables doesn't have a value.
When doing a minimum or maximum from scratch, a common approach is to start by assuming the first element is the candidate result, and then replace it if you find a better one on each step of the recursion. It also means you need to carry with you the last candidate at each recursive call, so that adds extra arguments:
minway([[N,L]|T], D, R) :-
minway(T, N, L, D, R).
minway([], D, R, D, R). % At the end, so D, R is the answer
minway([[N,L]|T], Dm, Rm, D, R) :-
( N < Dm
-> minway(T, N, L, D, R) % N, L are new candidates if N < Dm
; minway(T, N, Dm, Rm, D, R) % Dm, Rm are still best candidate
).
In Prolog, you can simplify this a little since Prolog has a more general term comparison operator, #<, #>, etc, which is smart about comparing more complex terms. For example, [2, [d,e,f]] #< [3, [a,b,c]] is true since 2 < 3 is true. We can then write:
minway([H|T], D, R) :-
minway(T, H, D, R).
minway([], [D, R], D, R).
minway([H|T], M, D, R) :-
( H #< M
-> minway(T, H, D, R)
; minway(T, M, D, R)
).
You can do this by using the minimum predicate. Findall can be very helpful.
min([X],X).
min([H|T],Min):-
min(T,TMin),
H>TMin,
Min is TMin.
min([H|T],Min):-
min(T,TMin),
H=<TMin,
Min is H.
minway(List,D,L):-
findall(Value,member([Value,_],List),VList),
min(VList,Min),
D=Min,
findall(EList,member([Min,EList],List),L).
?-minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).
D = 2,
L = [[a, b, d]]
Try library(aggregate):
?- aggregate_all(min(X,Y),
member([X,Y], [[3,[a,b,c,d]],
[2,[a,b,d]],
[5,[d,e,f]]]),
min(D,L)).
D = 2,
L = [a, b, d].
See also here:
Aggregation operators on backtrackable predicates
https://www.swi-prolog.org/pldoc/man?section=aggregate

Prolog: replacing an element in a list with another list

For the following query (and the predicates defined in the following) I get an unexpected answer:
?- rep([1,2,3], 3, [2,3,4], L).
L = [1, 2, 2, 3, 4] ;
L = [1, 2, 3]. % unexpected answer
The first result is the one I want. The second one I do not want...
How can I prevent the second one? Probably by adding ! somewhere?
concat([], L, L).
concat([H|T], L, [H|Res]) :-
concat(T, L, Res).
repl([], _, _, []).
repl([Val|T], Val, Repl, Res) :-
repl(T, Val, Repl, Temp),
concat(Repl, Temp, Res).
repl([H|T], Val, Repl, [H|Res]) :-
repl(T, Val, Repl, Res).
To allow for multiple matches per list, use meta-predicate maplist/3 and proceed like this:
item_replacement_item_mapped(E, Es, E, Es).
item_replacement_item_mapped(X, _, E, [E]) :-
dif(X, E).
repl(Es0,X,Xs,Es) :-
maplist(item_replacement_item_mapped(X,Xs), Es0, Ess1),
append(Ess1, Es).
Sample queries:
?- repl([1,2,3], 3, [2,3,4], L).
L = [1,2,2,3,4]
; false.
?- repl([x,y,x,y,x], x, [x,y,x], L).
L = [x,y,x,y,x,y,x,y,x,y,x]
; false.
As #repeat has already nicely shown, you should use the constraint dif/2 to describe that two terms are different. This avoids the unexpected and wrong second solution.
In addition, as always when describing lists, also consider using dcg notation: You can use the nonterminal list//1 do declaratively describe a list in such a way that it can be easily and efficiently spliced into other lists at specific positions.
Consider:
replacement([], _, _) --> [].
replacement([L|Ls], L, Rs) -->
list(Rs),
replacement(Ls, L, Rs).
replacement([L|Ls], R, Rs) --> [L],
{ dif(L, R) },
replacement(Ls, R, Rs).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
We use the interface predicate phrase/2 to use the DCG. For example:
?- phrase(replacement([1,2,3], 3, [2,3,4]), Ls).
Ls = [1, 2, 2, 3, 4] ;
false.
It is a true relation that works in all directions. It can answer quite general questions, such as: Which item has been replaced by another list? Example:
?- phrase(replacement([1,2,3], E, [2,3,4]), [1,2,2,3,4]).
E = 3 ;
false.
edit
this is getting hairy, and my answer didn't accounted precisely for request... so let's see your code with minimal change:
concat([], L, L).
concat([H|T], L, [H|Res]) :-
concat(T, L, Res).
repl([], _, _, []).
repl([Val|T], Val, Repl, Res) :- !, % as noted by #repeat, better to commit early...
repl(T, Val, Repl, Temp),
concat(Repl, Temp, Res). % !.
repl([H|T], Val, Repl, [H|Res]) :-
repl(T, Val, Repl, Res).
the cut simply commits the second clause...
resume old answer
your concat/3 is the same as the well known append/3, so consider this approach
repl(ListOrig, Element, Replace, ListUpdated) :-
append(H, [Element|T], ListOrig),
append(H, Replace, Temp),
append(Temp, T, ListUpdated).
?- repl([1, 2, 3], 3, [2, 3, 4], L).
L = [1, 2, 2, 3, 4] ;
false.
edit
as requested by comments, this extension handles a list of Element to match for change, with simple pattern matching (note: add before the previous clause)
repl(ListOrig, [], _Replace, ListOrig).
repl(ListOrig, [E|Es], Replace, ListUpdated) :-
repl(ListOrig, E, Replace, Temp),
repl(Temp, Es, Replace, ListUpdated).
test
?- repl([1,2,3],[2,3],[x,y,z],R).
R = [1, x, y, z, x, y, z] ;
false.
edit
I didn't noticed that if Element is not found it should not fail...
a last 'catchall' clause could handle this case:
repl(ListOrig, _Element, _Replace, ListOrig).
or better, extend the original like
repl(ListOrig, Element, Replace, ListUpdated) :-
( append(H, [Element|T], ListOrig)
-> append(H, Replace, Temp),
append(Temp, T, ListUpdated)
; ListOrig = ListUpdated
).

Prolog merge two lists

I need to merge two lists in Prolog. On input should be predicate merge/3.
Should work like this:
?- merge([6,4,b,8], [5,b,s,6], X).
X = [6, 4, b, 8, 5, s].
What I have tried:
%rules
merge(A, B, X):-
merge(A, B, B, X).
merge([], X, _, X).
merge([Head|L1], [Head|L2], Tmp, [Head|X]) :-
merge(L1, L2, Tmp, X),
!.
merge(L1, [_|L2], Tmp, X) :-
merge(L1, L2, Tmp, X),
!.
merge([A|L1], [], Tmp, [A|X]) :-
merge(L1, Tmp, Tmp, X),
!.
What I get:
?- merge([1,2,a,3], [5,d,a,1], X).
X = [1, 2, a, 3, 5, d, a, 1].
What I expect:
?- merge([1,2,a,3], [5,d,a,1], X).
X = [1, 2, a, 3, 5, d].
If the order of the elements does not somehow depend on the order of the two input lists, this is an idiomatic Prolog solution:
?- append([6,4,b,8], [5,b,s,6], A), sort(A, B).
A = [6, 4, b, 8, 5, b, s, 6],
B = [4, 5, 6, 8, b, s].
If the order is important, you need to explain how exactly.
And some comments on the code you show. The names that you have chosen for your predicates: both "join" and "merge" have well-established meanings different from what you seem to be attempting to achieve ("join" as in relational databases, "merge" as in "merge two ordered lists"). What you are doing is rather a "union" (and by the way, click on this link and read the code!).
Also, it is almost always a mistake (not an error, but a mistake) to have a cut as the last subgoal of a clause body. Having multiple clauses to a predicate that are not obviously mutually exclusive (as the last 3 of the 4 clauses to your merge/4) is commonly a design flaw (not a mistake).
This can be done by rewriting built-in predicates ! e.g :
my_append([], R, R) .
my_append([H|T], R1, [H|R2]) :-
my_append(T, R1, R2).
my_member(H, [H|_]).
my_member(H, [_|T]) :-
my_member(H, T).
So, I can say that merging L with an empty list gives this list L
merge(L, [], L).
Now, to merge two lists, I look at the first element of the second list.
If it is in the first list, I ignore it and I merge the first list, with the rest of the second.
If not, I add this first element at the end of the first list and I merge the new first list with the rest of the second.
I must say that it's not very efficient !!
merge(L, [H| T], R) :-
( my_member(H, L)
-> merge(L, T, R)
; my_append(L, [H], L1),
merge(L1, T, R)).