adding element into the List with prolog - prolog

I got a problem with this
I want to make a list of target position like if I type
?- extractIndices([5,6,7,8,9,5,6],6,List).
it should return
List = [1,6]
which gives all position of 6 in that list.
I wrote code like this:
extractIndices(List , Item, [Index | Indecis]) :-
indexOf(List , Item, Index).
indexOf([Item | _], Item, 0).
indexOf([_ |Tail], Item, Index):-
indexOf(Tail, Item, Index1),
Index is Index1+1.
and this gives me
?- extractIndices([5,6,7,8,9,5,6],6,L).
L = [1|_G2870] ;
L = [6|_G2870] ;
false.
It will be so thankful if someone can help me fix this...
Thank you.

You have provided two rules for indexOf, one which handles the head of the list, ignoring the tail, and one which handles the tail, ignoring the head. This results in two different solutions to your query as shown.
The predicate nth0 can be used to map positions to items in a list.
The easiest way to use it is going to be with findall:
extractIndices(List , Item, Indices) :-
findall(N, nth0(N, List, Item), Indices).
You can also make your own solution using something like indexOf. But you probably want to provide two different rules: one for the base case (usually an empty list), and one recursive case which solves it for the head, and then calls indexOf again on the tail.

I would use the same code as Edmund (i.e. findall + nth0), but for learning purpose a correction to your code it's worth to show:
extractIndices(List , Item, Indices) :-
indexOf(List, Item, 0, Indices).
indexOf([X|Items], Item, I, Is) :-
( X == Item -> Is = [I|Rs] ; Is = Rs ),
J is I + 1,
indexOf(Items, Item, J, Rs).
indexOf([], _, _, []).
test:
?- extractIndices([5,6,7,8,9,5,6],6,L).
L = [1, 6].

Related

How to combine elements of a list in different ways

I want to travel this type of list: [worker1(J, 10), worker2(T, 20), worker3(P, 30)].
, first starting by the head, combining it with the next element, and going till the end, and if at that point I do not reach a solution (my problem is affected by the order in which workers come), then I want start with another workers, and explore all other options.
I am not sure whether there is a simple way of doing this, but right now is the only idea I have to try and solve an exercise, so I wanted to ask here. The problem with what I know so far is that I would travel it like this:
w1-w2, w1-w3, w1-w4
if that fails, by recursion, I would skip the head and would have:
w2-w3, w2-w4
but not w2-w1, so I would be missing possible solutions. I found nothing when looking arround so my assumption is that I am not using proper terminology
If you Google "prolog combinations of a list", you'll find Prolog Guide - Combinatorics. Here's a slight variation of a predicate shown there that will generate sublists of N elements of a given list L:
comb(0, _, []).
comb(N, [X|T], [X|Comb]) :-
N #> 0,
N1 #= N - 1,
comb(N1, T, Comb).
comb(N, [_|T], [X|Comb]) :-
N #> 0,
comb(N, T, [X|Comb]).
To get all of the pairs you are after, you can call this with:
comb(2, List, Comb).
For example:
| ?- comb(2, [a,b,c,d], R).
R = [a,b] ? a
R = [a,c]
R = [a,d]
R = [b,c]
R = [b,d]
R = [c,d]
no
If you want dash pairs, you could just map them with:
pair_list_dash([X,Y], X-Y).

Prolog - List elements in a list of lists

I have a list and a list of lists:
A = [1,2,4,5]
L = [[1,2,5],[3,4,5]]
If A contains the same elements as one of the lists, I want it to return true. As A contains the same elements (1,2,5) as the first list in L ([1,2,5]), it should return true even though there's one element in A that isn't in the first list in L.
I've tried using a couple of predicates supplied in the answer of a similar question in order to solve this:
p(X):- findall( Y, (member(Y,X), \+ have_common_element(X,Y) ), [_]).
have_common_element(A,B):- member(X,A), memberchk(X,B).
However the following query will return false:
p([[[1,2,5],[3,4,5]],[1,2,4,5]]).
I understand that this is because there is an element in A (4) that isn't in the first list of L, although I'm having difficulty figuring out how to extend the predicates to have the query return true.
Would it be possible to extend these predicates so that true will be returned even with the additional (and non-mutual) element included?
What you want to say seems to be:
p(A, Ess) :-
member(Es, Ess), % there is a list Es in Ess
maplist(A+\E^member(E,A), Es). % for all E in Es: member(E,A).
or without lambdas:
p(A, Ess) :-
member(Es, Ess),
maplist(list_member(A), Es).
list_member(L, E) :-
member(E, L).

Prolog: Create list containing elements at even indices

Basically, I need to write a predicate, even_elts(L,M), such that L is a new list generated that contains only the even indexed elements from M (0th, 2nd, 4th, etc)
add_tail([X],[],X).
add_tail([H|NewT],[H|T],X) :-
add_tail(NewT,T,X).
even_elts(L,[]) :- L = [].
even_elts(L,M) :- even_elts2(L,M,1).
even_elts2(L,[H2|T2],Ct) :-
Ct2 is Ct + 1,
((Ct2 mod 2) =:= 0, add_tail(L,L2,H2), even_elts2(L2,T2,Ct2); even_elts2(L,T2,Ct2)).
even_elts2(_,[],_) :- !.
This works if M is empty or contains 1 or 2 elements. But, it only gets the first even indexed element from M, not the rest. Any pointers
EDIT: Solved the problem a different way, by removing the odd indexed elements rather than trying to create a new list and copying the data over. But, if someone can figure out a solution for my original code, I would be interested to see.
You're making this much more complicated than it is. You can use pattern matching to get each even element out, then collect those in the second (output) argument.
% an empty list does not have even elements
even_elts([], []).
% for all other lists, skip the second element (_),
% add the first to the output, recurse
even_elts([X, _ | L], [X | R]) :-
even_elts(L, R).
Just another approach with accumulator:
even_elts(L,M) :-
even_elts(M,0,[],L).
even_elts([H|T],I,Acc,Ans) :-
( I mod 2 =:= 0, append(Acc,[H], AccNew)
; I mod 2 =:= 1, AccNew = Acc
),
Inew is I + 1,
even_elts(T,Inew,AccNew,Ans).
even_elts([],_,Acc,Acc).
And
?- even_elts(X,[1,2,3,4,5]).
X = [1, 3, 5] ;
evens([A,B|C], [A|D]):- !, .....
evens(X, X).
is all you need. Fill in the blanks. :)

gprolog difference list with duplicate

i have to get list difference between two integer list (both ordinate).
i white this:
difference(L,[],L) :- !.
difference([],_,[]) :- !.
difference([],[],W).
difference([H|T1],[D|T2],T3) :- difference(T1,[D|T2],[H|T3]).
difference([H|T1],[H|T2],T3) :- difference(T1,T2,T3).
but why i can't get my list difference?
if i write this:
difference([],[],W):- write(X).
and this example:
| ?- difference([1,4,4],[1,4],R).
[4|_27]
it makes right!
NB if i have duplicate number i have to show it!
I find your code rather odd. For instance, your third clause: what's W for? Seems like you mean to say:
difference([],[],_).
Second problem: in the fourth clause, there's nothing stopping H and D from being independent variables with the same binding. I suspect you mean something like this:
difference([H|T1],[D|T2],T3) :- H \= D, difference(T1,[D|T2],[H|T3]).
Fixing these things seems to fix the predicate to give a reasonable looking answer:
| ?- difference([1,4,4], [1,4], R).
R = [4]
I think your first several clauses are trying to handle different sorts of base cases, is that right? E.g.:
difference(L, [], L) % handles the case where the second list is exhausted
difference([], _, []) % handles the case where the first list is exhausted
difference([], [], W) % handles the case where the lists are exhausted at the same time
One problem with this is that L = [] is a legitimate binding, so the first and third clauses mean the same thing. You can probably safely remove the third one, because it would have matched and produced the same answer on the first. The second clause is more interesting, because it seems to say that regardless of whatever work we've done so far, if the first list is empty, the result is empty. I find that possibility a bit jarring--is it possible you actually want these two base cases? :
difference([], L, L).
difference(L, [], L).
I remain unconvinced, but until I have a better idea what you're trying to accomplish I may not be able to help more. For instance, what should happen with difference([1, 4], [1, 4, 4], R)? I posit you probably want R = [4], but your code will produce R = [].
Also, I find it unlikely that
difference([],[],W):- write(X).
is going to be a helpful debugging strategy, because Prolog will generate a new variable binding for X because there's nothing for it to refer to.
The final version I have with all my changes looks like this:
difference(L, [], L) :- !.
difference([], L, L) :- !.
difference([H|T1], [D|T2], T3) :- D \= H, difference(T1, [D|T2], [H|T3]).
difference([H|T1], [H|T2], T3) :- difference(T1, T2, T3).
Edit: does this implement your requirements?
not_in1(X, Left, Right) :- member(X, Left), \+ member(X, Right).
not_in(X, Left, Right) :- not_in1(X, Left, Right).
not_in(X, Left, Right) :- not_in1(X, Right, Left).
differences(Left, Right, Differences) :-
findall(X, not_in(X, Left, Right), Differences).
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
If so, I'll try to get your original code to produce answers that match.
Edit 2: OK, so the problem with the solution above is that it is O(N^2). In the worst case (two totally distinct lists) it will have to compare every item from list 1 to every item of list 2. It's not exploiting the fact that both lists are ordered (I believe that's what you mean by 'ordinate').
The result looks a lot more like your original code, but your original code is not taking advantage of the fact that the items are ordered. This is why the fourth and fifth cases are confusing looking: you should recur down one of the lists or the other depending on which number is larger. The corrected code looks like this:
differences([], Result, Result).
differences(Result, [], Result).
differences([H|Ls], [H|Rs], Result) :- differences(Ls, Rs, Result).
differences([L|Ls], [R|Rs], [L|Result]) :-
L < R,
differences(Ls, [R|Rs], Result).
differences([L|Ls], [R|Rs], [R|Result]) :-
L > R,
differences([L|Ls], Rs, Result).
You can see this produces the same result as the O(N^2) method:
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
You were right, you do need both base cases. This is so the remainder of either list becomes part of the result. Presumably these will be the largest values ([5] in the example).
Now I have three inductive cases: one for <, one for > and one for =. The equality case is intuitive: recur on both lists, discarding the head of both lists. The next case basically says if the left head is less than the right head, add it to the result and recur on the left's tail. The right is unchanged in that case. The other case is the mirror of this case.
Hope this helps!

Pattern matching list of lists

I have a problem where I have a list like this:
[[el1, el2, el3],
[el4, el5, el6],
[[el7, el8, el9], [el10, el11, el12], ..... , [elxx, elyy, elzz]],
[el, el, el]...]]
I want to pattern match the inner list of lists, the
[el7, el8, el9], [el10, el11, el12], ..... , [elxx, elyy, elzz]
How can this be done?
As of now I patternmatch the other elements with
my_method([[El1, El2, El3] | Rest]).
UPDATE
I want to pattern match if the next item of the list is a list of lists - I will be iterating over this list, removing item after item. There can be any number of lists of lists, and they can contain any number of items. They can also contain lists of lists. In fact, I will recursively call the same processing method whenever I come upon a list of lists.
All bottom level lists will have three elements, however these elements might be different:
[1, p, neg(5,6)]
[5, neg(7,6), assumption]
You said "I will be iterating over this list, removing item after item", so here's code that does just that, assuming an "item" is a three-element list of non-lists.
nested_member(X,X) :-
X = [A,_,_],
\+ is_list(A).
nested_member(X,[L|_]) :-
nested_member(X,L).
nested_member(X,[_|L]) :-
nested_member(X,L).
This can be used to backtrack over the "items":
?- nested_member(X,[[el1, el2, el3], [el4, el5, el6],
[[el7, el8, el9], [el10, el11, el12],[elxx, elyy, elzz]]]).
X = [el1, el2, el3] ;
X = [el4, el5, el6] ;
X = [el7, el8, el9] ;
X = [el10, el11, el12] ;
X = [elxx, elyy, elzz] ;
false.
I you want, you can even find out how deep in the list the items were found:
nested_member(X,L,D) :-
nested_member(X,L,0,D).
nested_member(X,X,D,D) :-
X = [A,_,_],
\+ is_list(A).
nested_member(X,[L|_],D0,D) :-
D1 is D0+1,
nested_member(X,L,D1,D).
nested_member(X,[_|L],D0,D) :-
nested_member(X,L,D0,D).
You can use predicates similar to the following.
qualify([], []).
qualify([H|T], [HN|TN]) :- qualify_one(H, HN), qualify(T, TN).
qualify_one([H|_], N) :- qualify_one(H, N1), N is N1 + 1, !.
qualify_one(_, 0).
What qualify does is for each member of the list to find out on what level of the scale “not a list”, “simple list”, “list of lists”, … it is, based on the first item.
Example:
?- qualify([1,[2,3,3],[[4,5,6], [7,8,9]]], NS).
NS = [0, 1, 2].

Resources