Prolog Lists from List Predicate - list

I am trying to make a code in which the input is a list with lists and non-lists within it and the output is a list with the lists from the first input. So, for example input listsFromList([2,3,6,[a,g],2,3,[c,d]],X). The output would be X = [[a,g],[c,d]]. I am trying to do it with an accumulator.
So I made this code:
listsFromList([],A) :- A.
listsFromList([H|SOURCEs],A) :-
is_list(H),
append([A],H,A),
listsFromList(SOURCEs,A).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
It does not work if I put more than one list in the first list and also it gives a wrong output when I put one list in it. Can anyone help?

You need to modify few things. Here a solution with the same number of arguments:
listsFromList([],[]).
listsFromList([H|SOURCEs],[H|A1]) :-
is_list(H),
listsFromList(SOURCEs,A1).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]];
false
If you want to use append/3, you could add an accumulator list (so increase the arity form 2 to 3), but this is unnecessary, or swap the position of append/3. Furthermore, you can add a cut (!) to avoid the false solution.
Solution wiht accumulator:
listsFromList([],L,L).
listsFromList([H|SOURCEs],LIn,LO) :-
is_list(H),
append([H],LIn,L),
listsFromList(SOURCEs,L,LO).
listsFromList([H|SOURCEs],L,LO) :-
\+ is_list(H),
listsFromList(SOURCEs,L,LO).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],[],X).
X = [[c, d], [a, g]]
false
If you want to use append/2 with arity 2 of the main predicate, use:
listsFromList([],[]).
listsFromList([H|SOURCEs],L) :-
is_list(H),
listsFromList(SOURCEs,L1),
append([H],L1,L).
listsFromList([H|SOURCEs],A) :-
\+ is_list(H),
listsFromList(SOURCEs,A).
?- listsFromList([2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]]
false
If you want to be super fancy and super short, you can solve your problem (assuming you are running SWI Prolog) with one line:
?- include(is_list,[2,3,6,[a,g],2,3,[c,d]],X).
X = [[a, g], [c, d]]

Related

SWI Prolog - Combining elements from two lists into pairs

How can I "join" two lists while keeping their elements's positions? Like, I have List1 = [1,2,3] and List2 = [a,b,c]. How can I get the list [[1,a], [2,b], [3,c]]?
I've been trying to look for built-in predicates but all I've found can't reproduce this.
join_2_lists(L1, L2, JoinLst) :-
must_be(list, L1),
must_be(list, L2),
join_2_lists_(L1, L2, JoinLst).
join_2_lists_([], [], []).
join_2_lists_([H1|T1], [H2|T2], [[H1, H2]|JoinLst]) :-
join_2_lists_(T1, T2, JoinLst).
Result in swi-prolog:
?- join_2_lists([1, 2, 3], [a, b, c], J).
J = [[1,a],[2,b],[3,c]].

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.

Can anyone help me in writing a prolog program for deleting a list?

Ex: If I have been given two list [1,4,3,2,5,6] and [1,2,3] the final list should be [4,5,6].
i.e., Del([1,4,3,2,5,6], [1,2,3], Result).
----should output Result=[4,5,6].
I have tried something like this:
delete1(A, [A|B], B).
delete1(A, [B, C|D], [B|E]) :- delete1(A, [C|D], E).
But the output I'm getting is by deleting the element being passed as an parameter and not a list.
Output:
delete1(a,[a,b,c,d],Res).
(0) Call: delete1(a,[a,b,c,d],_h210) ?
(0) Exit: delete1(a,[a,b,c,d],[b,c,d]) ?
Res = [b,c,d]
Can anyone please help me how to go about this ?
Pure and simple: Use meta-predicate tfilter/3 in tandem with list_nonmember_t/3!
Like we did with memberd_t/3, we define list_nonmember_t/3 based on if_/3 and (=)/3:
list_nonmember_t([],_,true).
list_nonmember_t([E|Es],X,T) :-
if_(E=X, T=false, list_nonmember_t(Es,X,T)).
Let's put it together!
?- tfilter(list_nonmember_t([1,2,3]), [1,4,3,2,5,6], Xs).
Xs = [4,5,6]. % succeeds deterministically
del1([], _, []).
del1([A|L], B, R) :- member(A, B), del1(L, B, R).
del1([A|L], B, [A|R]) :- not(member(A,B)), del1(L, B, R).
So your delete1 is a good start, it allows to delete single element from the list, but it is not handling all of the cases. For example the lists that are not containing the element to be deleted.
So the right one would be :
delete1(_, [], []).
delete1(A, [A|B], B).
delete1(A, [C|B], [C|E]) :- delete1(A, B, E).
and then using this, you can define your del1 by applying delete1 recursively on the whole list:
del1([], _, []).
del1(L, [], L).
del1(L, [H|T], R) :-
delete1(H, L, R1),
del1(R1, T, R).
And of course you can use builtin list predicates as stated in the other answer.

Adding an element to a sublist

I need to define a predicate toAdd/3 such that if Xss and Yss are lists of lists then toAdd(X,Xss,Yss) holds if Yss can be obtained by adding the element X to the end of every element in Xss, e.g.
?- toAdd(g, [[e],[b,c,f],[k,h]], Yss).
Yss = [[e,g],[b,c,f,g],[k,h,g]]. % expected result
I know how to add an element to a list but lists of lists confuse me.
I wrote this code that adds to the end of one list, but not sublists.
add(X,[],[X]).
add(X,[A|L],[A|L1]) :-
add(X,L,L1).
Let's put the predicate add/3 to use with meta-predicate maplist/3!
toAdd(X,Xss,Yss) :-
maplist(add(X),Xss,Yss).
Sample query:
?- toAdd(g, [[e],[b,c,f],[k,h]], Yss).
Yss = [[e,g],[b,c,f,g],[k,h,g]]
; false.
split the problem in two parts:
- transform each element
- append to tail
then
add(_,[],[]). % done
add(X,[E|Es],[T|Ts]) :-
append(E,[X],T),
add(X,Es,Ts).
we can do inline using findall/3 and member/2
1 ?- [user].
|: tooAdd(X, Es, Ts) :- findall(T, (member(E,Es),append(E,[X],T)), Ts).
% user://1 compiled 71.19 sec, 2 clauses
true.
2 ?- tooAdd(g, [[e], [b, c, f], [k, h]], Yss).
Yss = [[e, g], [b, c, f, g], [k, h, g]].

Prolog lists difference

I'm trying to make program in prolog that will do something like this:
diffSet([a,b,c,d], [a,b,e,f], X).
X = [c,d,e,f]
I wrote this:
diffSet([], _, []).
diffSet([H|T1],Set,Z):- member(Set, H), !, diffSet(T1,Set,Z).
diffSet([H|T], Set, [H|Set2]):- diffSet(T,Set,Set2).
But in that way I can only get elements from the first list. How can I extract the elements from the second one?
#edit:
member is checking if H is in Set
member([H|_], H).
member([_|T], H):- member(T, H).
There is a builtin that remove elements from the list:
diffSet([], X, X).
diffSet([H|T1],Set,Z):-
member(H, Set), % NOTE: arguments swapped!
!, delete(T1, H, T2), % avoid duplicates in first list
delete(Set, H, Set2), % remove duplicates in second list
diffSet(T2, Set2, Z).
diffSet([H|T], Set, [H|Set2]) :-
diffSet(T,Set,Set2).
Or using only built-ins. if you wanted to just get the job done:
notcommon(L1, L2, Result) :-
intersection(L1, L2, Intersec),
append(L1, L2, AllItems),
subtract(AllItems, Intersec, Result).
?- notcommon([a,b,c,d], [a,b,e,f], X).
X = [c, d, e, f].
Deliberately avoiding the built ins for this that #chac mentions, this is an inelegant way that does the job.
notcommon([], _, []).
notcommon([H1|T1], L2, [H1|Diffs]) :-
not(member(H1, L2)),
notcommon(T1, L2, Diffs).
notcommon([_|T1], L2, Diffs) :-
notcommon(T1, L2, Diffs).
alldiffs(L1, L2, AllDiffs) :-
notcommon(L1, L2, SetOne),
notcommon(L2, L1, SetTwo),
append(SetOne, SetTwo, AllDiffs).
? alldiffs([a,b,c,d], [a,b,e,f], X).
X = [c, d, e, f] .