Related
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]].
List1=[(x,1),(y,1),(z,1)]
I'm attempting to split this list:
into two lists:
List3=[x,y,z]
List4=[1,1,1]
So I have written this predicate to try to do it:
splt([], [], []).
splt([X|Xs], [Y|Ys], [X,Y|Zs]) :-
splt(Xs,Ys,Zs).
However instead of the desired result, the predicate returns:
1 ?- splt([(x,1),(y,2),(z,3)],L3,L4).
L3 = [_G1760, _G1769, _G1778],
L4 = [ (z, 1), _G1760, (y, 2), _G1769, (z, 3), _G1778].
First, the term you have chosen. This: (a, b), is most definitely not how you would usually represent a "tuple" in Prolog. You almost always use a-b for a "pair", and pairs are used throughout the standard libraries.
So your initial list would look like this: [x-1, y-1, z-1].
This should also explain why you are having your problem. You write (a, b), but your predicate says a, b, and you consume two elements when you expect to get one ,(a,b) term. So, to fix your current predicate you would write:
split([], [], []).
split([X|Xs], [Y|Ys], [(X,Y)|XYs]) :-
split(Xs, Ys, XYs).
?- split(Xs, Ys, [(x,1), (y,1), (z,1)]).
Xs = [x, y, z],
Ys = [1, 1, 1].
But instead, using a more conventional name, term order, and Prolog pairs:
zip([], [], []).
zip([X-Y|XYs], [X|Xs], [Y|Ys]) :-
zip(XYs, Xs, Ys).
?- zip([x-1, y-1, z-1], Xs, Ys).
Xs = [x, y, z],
Ys = [1, 1, 1].
And of course, SWI-Prolog at least has a library(pairs), and it comes with a pairs_keys_values/3:
?- pairs_keys_values([x-1, y-1, z-1], Xs, Ys).
Xs = [x, y, z],
Ys = [1, 1, 1].
I find comfortable using library(yall):
?- maplist([(X,Y),X,Y]>>true, [(x,1),(y,2),(z,3)],L3,L4).
L3 = [x, y, z],
L4 = [1, 2, 3].
or, maybe clearer
?- maplist([A,B,C]>>(A=(B,C)), [(x,1),(y,2),(z,3)],L3,L4).
L3 = [x, y, z],
L4 = [1, 2, 3].
You're matching the tuple as a whole, rather than it's component parts.
You should match on [(X1,Y1)|XS], instead of [X|XS] and [Y|Ys].
splt([],[],[]).
splt([(X1,Y1)|Xs],[X1|T1],[Y1|T2]):-
splt(Xs,T1,T2).
Here the first term is used as input, the second and third as output.
Ideone example, using SWI-Prolog, here.
I am trying to remove duplicates from a list while keeping the rightmost occurrences. E.g.: [1,2,3,1,2] is transformed in [3,1,2]
It's one of my first tries in Prolog and I don't understand what am I doing wrong. It always returns false. This is my code:
%nrap(L:list,E:element,S:integer)
%L - the initial list, list of integers
%E - the element, integer
%S - the result, nrap of E in L, S integer
%flow model: (i,i,o),(i,i,i)
nrap([],_,0).
nrap([H|T],E,S):-
H=E,
nrap(T,E,S1),
S is S1+1.
nrap([H|T],E,S):-
H\=E,
nrap(T,E,S).
%transform(L:list,L2:list,R:list)
%L - the initial list, list of integers
%L2 - copy of the initial list
%R - the resulted list, without duplicates, list of integers
%flow model: (i,i,o),(i,i,i)
transform([],[],[]).
transform([H|T],L2,[H|R]):-
nrap(L2,H,S),
S=1,
transform(T,L2,R).
transform([H|T],L2,R):-
nrap(L2,H,S),
S>1,
transform(T,L2,R).
Shall I be pure or impure? Why even consider sacrificing logical-purity if we can save it easily!
Using memberd_t/3 and if_/3, we define list_rset/2 and its left "twin" list_lset/2:
list_rset([], []). % keep rightmost occurrences
list_rset([E|Es], Rs0) :-
if_(memberd_t(E, Es),
Rs0 = Rs,
Rs0 = [E|Rs]),
list_rset(Es, Rs).
list_lset([], []). % keep leftmost occurrences
list_lset([E|Es], Ls) :-
post_pre_lset(Es, [E], Ls). % uses internal auxilary predicate
post_pre_lset([], _, []).
post_pre_lset([E|Es], Pre, Ls0) :- % 2nd arg: look-behind accumulator
if_(memberd_t(E, Pre),
Ls0 = Ls,
Ls0 = [E|Ls]),
post_pre_lset(Es, [E|Pre], Ls).
Let's run some queries!
?- _Es = [1,2,3,1,2], list_lset(_Es, Ls), list_rset(_Es, Rs).
Ls = [1,2,3], Rs = [3,1,2]. % succeeds deterministically
In above query 1 precedes 2 both at the beginning and at the end of the list [1,2,3,1,2]. What if 1 precedes 2 at the beginning but follows it at the end (e.g., [1,2,3,2,1])?
?- _Es = [1,2,3,2,1], list_lset(_Es, Ls), list_rset(_Es, Rs).
Ls = [1,2,3], Rs = [3,2,1]. % succeeds deterministically
Next, we look at a more general list_rset/2 goal that uses a list containing variables only. Thanks to #PauloMoura for his suggestion!
?- Es = [A,B,C,A,B], list_rset(Es,Rs).
Es = [C,C,C,C,C], Rs = [ C], A=B , B=C
; Es = [B,B,C,B,B], Rs = [C, B], A=B , dif(B,C)
; Es = [C,B,C,C,B], Rs = [ C,B], A=C , dif(B,C)
; Es = [A,C,C,A,C], Rs = [ A,C], dif(A,C), B=C
; Es = [A,B,C,A,B], Rs = [C,A,B], dif(A,B), dif(A,C), dif(B,C).
What's up with the residual goals (above)?
Without sufficient instantiation, dif/2 is not decidable.
To save logical soundness, the execution of the prolog-dif constraints is delayed.
Last, one more use-case: an "input" list Xs that has both variables and ground terms.
?- Es = [A,B,z], list_rset(Es,Rs).
Es = [z,z,z], Rs = [ z], A=B , B=z
; Es = [B,B,z], Rs = [B, z], A=B , dif(B,z)
; Es = [z,B,z], Rs = [ B,z], A=z , dif(B,z)
; Es = [A,z,z], Rs = [A, z], dif(A,z), B=z
; Es = [A,B,z], Rs = [A,B,z], dif(A,B), dif(A,z), dif(B,z).
This is a follow-up to this previous answer... In this answer we use dcg!
We build lset//1 upon memberd_t/3 and if_//3—the dcg analogue of if_/3:
lset([]) -->
[].
lset([X|Xs]) -->
[X],
lset_pre(Xs,[X]).
lset_pre([],_) -->
[].
lset_pre([X|Xs],Pre) -->
if_(memberd_t(X,Pre), [], [X]),
lset_pre(Xs,[X|Pre]).
Same for rset//1:
rset([]) -->
[].
rset([X|Xs]) -->
if_(memberd_t(X,Xs), [], [X]),
rset(Xs).
Some sample queries:
?- _Es = [1,2,3,1,2], phrase(lset(_Es),Ls), phrase(rset(_Es),Rs).
Ls = [1,2,3], Rs = [3,1,2]. % succeeds deterministically
?- _Es = [1,2,3,2,1], phrase(lset(_Es),Ls), phrase(rset(_Es),Rs).
Ls = [1,2,3], Rs = [3,2,1]. % succeeds deterministically
This is easier than you are making it. Since the elements in the "set" have to be in the order of last appearance, you don't need to keep a copy of the list at all: just compare to the remainder of the list (the tail).
If you know that the first list is always going to be ground (all elements are integers, for example), you could write:
list_set([], []).
list_set([X|Xs], Ys0) :-
( memberchk(X, Xs)
-> Ys0 = Ys
; Ys0 = [X|Ys]
),
list_set(Xs, Ys).
memberchk/2 can be used to check if a ground term is in a list of ground terms. It will succeed or fail exactly once.
A more general solution is to pose a constraint that an element should be in the set if it is different from all the elements following it, and be dropped otherwise:
list_set([], []).
list_set([X|Xs], [X|Ys]) :-
maplist(dif(X), Xs),
list_set(Xs, Ys).
list_set([X|Xs], Ys) :-
\+ maplist(dif(X), Xs),
list_set(Xs, Ys).
Here, maplist(dif(X), Xs) means:
X is different from every element in the list Xs (the tail).
and \+ Goal succeeds then Goal does not succeed.
With this defintion:
?- list_set([1,2,3,1,2], S).
S = [3, 1, 2] ;
false.
?- list_set([1,2,3,3,1,1,2], S).
S = [3, 1, 2] ;
false.
?- list_set([A,B,C,A,B],Xs).
Xs = [C, A, B],
dif(A, B),
dif(C, B),
dif(C, A) ;
false.
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]].
i'm starting up learning prolog (i use SWI-prolog) and i did a simple exercise in which i have 2 lists and i want to calculate their intersection and union.
Here is my code that works pretty well but i was asking myself if there is a better way to do it as i don't like to use the CUT operator.
intersectionTR(_, [], []).
intersectionTR([], _, []).
intersectionTR([H1|T1], L2, [H1|L]):-
member(H1, L2),
intersectionTR(T1, L2, L), !.
intersectionTR([_|T1], L2, L):-
intersectionTR(T1, L2, L).
intersection(L1, L2):-
intersectionTR(L1, L2, L),
write(L).
unionTR([], [], []).
unionTR([], [H2|T2], [H2|L]):-
intersectionTR(T2, L, Res),
Res = [],
unionTR([], T2, L),
!.
unionTR([], [_|T2], L):-
unionTR([], T2, L),
!.
unionTR([H1|T1], L2, L):-
intersectionTR([H1], L, Res),
Res \= [],
unionTR(T1, L2, L).
unionTR([H1|T1], L2, [H1|L]):-
unionTR(T1, L2, L).
union(L1, L2):-
unionTR(L1, L2, L),
write(L).
Keep in mind that i want to have just 1 result, not multiple results (even if correct) so running the code with this:
?- intersect([1,3,5,2,4] ,[6,1,2]).
should exit with:
[1,2]
true.
and not with
[1,2]
true ;
[1,2]
true ;
etc...
The same must be valid for union predicate.
As i said my code works pretty well but please suggest better ways to do it.
Thanks
Also, not sure why you're dead against cuts, so long as their removal would not change the declaritive meaning of the code, as per your link. For example:
inter([], _, []).
inter([H1|T1], L2, [H1|Res]) :-
member(H1, L2),
inter(T1, L2, Res).
inter([_|T1], L2, Res) :-
inter(T1, L2, Res).
test(X):-
inter([1,3,5,2,4], [6,1,2], X), !.
test(X).
X = [1, 2].
In the test bit where I call the code, I'm just saying do the intersection but I'm only interested in the first answer. There are no cuts in the predicate definitions themselves.
The following is based on my previous answer to Remove duplicates in list (Prolog);
the basic idea is, in turn, based on #false's answer to Prolog union for A U B U C.
What message do I want to convey to you?
You can describe what you want in Prolog with logical purity.
Using if_/3 and (=)/3 a logically pure implementation can be
both efficient (leaving behind choice points only when needed)
and monotone (logically sound with regard to generalization / specialization).
The implementation of #false's predicates if_/3 and (=)/3 does use meta-logical Prolog features internally, but (from the outside) behaves logically pure.
The following implementation of list_list_intersection/3 and list_list_union/3 uses list_item_isMember/3 and list_item_subtracted/3, defined in a previous answer:
list_list_union([],Bs,Bs).
list_list_union([A|As],Bs1,[A|Cs]) :-
list_item_subtracted(Bs1,A,Bs),
list_list_union(As,Bs,Cs).
list_list_intersection([],_,[]).
list_list_intersection([A|As],Bs,Cs1) :-
if_(list_item_isMember(Bs,A), Cs1 = [A|Cs], Cs1 = Cs),
list_list_intersection(As,Bs,Cs).
Here's the query you posted as part of your question:
?- list_list_intersection([1,3,5,2,4],[6,1,2],Intersection).
Intersection = [1, 2]. % succeeds deterministically
Let's try something else... The following two queries should be logically equivalent:
?- A=1,B=3, list_list_intersection([1,3,5,2,4],[A,B],Intersection).
A = 1,
B = 3,
Intersection = [1, 3].
?- list_list_intersection([1,3,5,2,4],[A,B],Intersection),A=1,B=3.
A = 1,
B = 3,
Intersection = [1, 3] ;
false.
And... the bottom line is?
With pure code it's easy to stay on the side of logical soundness.
Impure code, on the other hand, more often than not acts like "it does what it should" at first sight, but shows all kinds of illogical behaviour with queries like the ones shown above.
Edit 2015-04-23
Neither list_list_union(As,Bs,Cs) nor list_list_intersection(As,Bs,Cs) guarantee that Cs doesn't contain duplicates. If that bothers you, the code needs to be adapted.
Here are some more queries (and answers) with As and/or Bs containing duplicates:
?- list_list_intersection([1,3,5,7,1,3,5,7],[1,2,3,1,2,3],Cs).
Cs = [1, 3, 1, 3].
?- list_list_intersection([1,2,3],[1,1,1,1],Cs).
Cs = [1].
?- list_list_union([1,3,5,1,3,5],[1,2,3,1,2,3],Cs).
Cs = [1, 3, 5, 1, 3, 5, 2, 2].
?- list_list_union([1,2,3],[1,1,1,1],Cs).
Cs = [1, 2, 3].
?- list_list_union([1,1,1,1],[1,2,3],Cs).
Cs = [1, 1, 1, 1, 2, 3].
Edit 2015-04-24
For the sake of completeness, here's how we could enforce that the intersection and the union are sets---that is lists that do not contain any duplicate elements.
The following code is pretty straight-forward:
list_list_intersectionSet([],_,[]).
list_list_intersectionSet([A|As1],Bs,Cs1) :-
if_(list_item_isMember(Bs,A), Cs1 = [A|Cs], Cs1 = Cs),
list_item_subtracted(As1,A,As),
list_list_intersectionSet(As,Bs,Cs).
list_list_unionSet([],Bs1,Bs) :-
list_setB(Bs1,Bs).
list_list_unionSet([A|As1],Bs1,[A|Cs]) :-
list_item_subtracted(As1,A,As),
list_item_subtracted(Bs1,A,Bs),
list_list_unionSet(As,Bs,Cs).
Note that list_list_unionSet/3 is based on list_setB/2, defined here.
Now let's see both list_list_intersectionSet/3 and list_list_unionSet/3 in action:
?- list_list_unionSet([1,2,3,1,2,3,3,2,1],[4,5,6,2,7,7,7],Xs).
Xs = [1, 2, 3, 4, 5, 6, 7].
?- list_list_intersectionSet([1,2,3,1,2,3,3,2,1],[4,5,6,2,7,7,7],Xs).
Xs = [2].
Edit 2019-01-30
Here is an additional query taken from #GuyCoder's comment (plus two variants of it):
?- list_list_unionSet(Xs,[],[a,b]).
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
...
?- list_list_unionSet([],Xs,[a,b]).
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
...
?- list_list_unionSet(Xs,Ys,[a,b]).
Xs = [], Ys = [a,b]
; Xs = [], Ys = [a,b,b]
; Xs = [], Ys = [a,b,b,b]
...
With the old version of list_item_subtracted/3, above queries didn't terminate existentially.
With the new one they do.
As the solution set size is infinite, none of these queries terminate universally.
To cheat slightly less than my first answer, you could use the findall higher order predicate which gets Prolog to do the recursion for you :
4 ?- L1=[1,3,5,2,4], L2=[6,1,2], findall(X, (nth0(N, L1, X), member(X, L2)), Res).
L1 = [1, 3, 5, 2, 4],
L2 = [6, 1, 2],
Res = [1, 2].
If the aim is to just 'get the job done', then swi prolog has built in primitives for exactly this purpose:
[trace] 3 ?- intersection([1,3,5,2,4] ,[6,1,2], X).
intersection([1,3,5,2,4] ,[6,1,2], X).
X = [1, 2].
[trace] 4 ?- union([1,3,5,2,4] ,[6,1,2], X).
X = [3, 5, 4, 6, 1, 2].
Try this, analogue to union/3 here:
:- use_module(library(clpfd)).
member(_, [], 0).
member(X, [Y|Z], B) :-
(X #= Y) #\/ C #<==> B,
member(X, Z, C).
intersect([], _, []).
intersect([X|Y], Z, T) :-
freeze(B, (B==1 -> T=[X|R]; T=R)),
member(X, Z, B),
intersect(Y, Z, R).
It works if the elements are integer, and doesn't leave any choise point:
?- intersect([X,Y],[Y,Z],L).
freeze(_15070, (_15070==1->L=[X, Y];L=[Y])),
_15070 in 0..1,
_15166#\/_15168#<==>_15070,
_15166 in 0..1,
X#=Y#<==>_15166,
X#=Z#<==>_15168,
Y#=Z#<==>_15258,
_15168 in 0..1,
_15258 in 0..1.
?- intersect([X,Y],[Y,Z],L), X=1, Y=2, Z=3.
X = 1,
Y = 2,
Z = 3,
L = [2].
?- intersect([X,Y],[Y,Z],L), X=3, Y=2, Z=3.
X = Z, Z = 3,
Y = 2,
L = [3, 2].
And finally (really), you could use findall to find all the solutions, then use nth0 to extract the first one, which will give you the result you want without cuts, and keeps the predicates nice and clean, without have any additional predicates to trap/stop prolog doing what it does best - backtracking and finding multiple answers.
Edit: It's arguable that putting in extra predicates in the 'core logic' to prevent multiple results being generated, is as ugly/confusing as using the cuts that you are trying to avoid. But perhaps this is an academic exercise to prove that it can be done without using higher order predicates like findall, or the built-ins intersection/union.
inter([], _, []).
inter([H1|T1], L2, [H1|Res]) :-
member(H1, L2),
inter(T1, L2, Res).
inter([_|T1], L2, Res) :-
inter(T1, L2, Res).
test(First):-
findall(Ans, inter([1,3,5,2,4], [6,1,2], Ans), Ansl),
nth0(0, Ansl, First).
% Element X is in list?
pert(X, [ X | _ ]).
pert(X, [ _ | L ]):- pert(X, L).
% Union of two list
union([ ], L, L).
union([ X | L1 ], L2, [ X | L3 ]):- \+pert(X, L2), union(L1, L2, L3).
union([ _ | L1 ], L2, L3):- union(L1, L2, L3).
% Intersection of two list
inter([ ], _, [ ]).
inter([ X | L1 ], L2, [ X | L3 ]):- pert(X, L2), inter(L1, L2, L3).
inter([ _ | L1 ], L2, L3):- inter(L1, L2, L3).
I know this post is very old but I found a solution with minimum coding.
% intersection
intersection([],L1,L2,L3).
intersection([H|T],L2,L3,[H|L4]):-member(H,L2),intersection(T,L3,L3,L4).
% member
member(H,[H|T]).
member(X,[H|T]):-member(X,T).
To test the above code you should not enter L3. Here is an examples.
?- intersection([w,4,g,0,v,45,6],[x,45,d,w,30,0],L).
L = [w, 0, 45].