Pattern matching list of lists - prolog

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].

Related

Given a list of elements, replicate each element N times

I have to replicate each element n times like this:
?- replicate([a,b,c],2,X). -> X = [a,a,b,b,c,c]
?- replicate([a,b,c],3,X). -> X = [a,a,a,b,b,b,c,c,c]
I have tried everything with the information I have so far, the only thing I have been able to do is to determine which is the most repeating element like this:
%List of tuples, keeps track of the number of repetitions.
modify([],X,[(X,1)]).
modify([(X,Y)|Xs],X,[(X,K)|Xs]):- K is Y+1.
modify([(Z,Y)|Xs],X,[(Z,Y)|K]):- Z =\= X, modify(Xs,X,K).
highest((X1,Y1),(_,Y2),(X1,Y1)):- Y1 >= Y2.
highest((_,Y1),(X2,Y2),(X2,Y2)):- Y2 > Y1.
maxR([X],X).
maxR([X|Xs],K):- maxR(Xs,Z),highest(X,Z,K).
rep([],R,R).
rep([X|Xs],R,R1):-modify(R,X,R2),rep(Xs,R2,R1).
maxRepeated(X,R):- rep(X,[],K),maxR(K,R).
?- maxRepeated([1,3,3,4,3,2] ,X).
X = (3, 3) .
?- maxRepeated([1,2,3,4,5,6] ,X).
X = (1, 1) .
What do you want to do ?
Take each element X of the list, get a list of N X and create a new list with the process of the rest of the list !
How to get a list of N elements X ?
replicate_one(X, N, Out) :-
length(Out, N),
maplist(=(X),Out).
Now, how to work with each element of the input, it can be easily done with the pattern [Head|Tail] :
replicate([Head|Tail], N, Out) :-
% I replicate the rest of the list
replicate(Tail, N, Tmp1),
% I replicate the first element of the list
replicate_one(Head, N, Tmp2),
% I concatenate the 2 results
append(Tmp2, Tmp1, Out).
When you work with replicate, the input looses an element each time, so you must have a process for the empty list :
replicate([], _N, []).
Now :
?- replicate([a,b,c],3,X).
X = [a, a, a, b, b, b, c, c, c].
We can split the problem into two problems:
generate a list of N elements X with a predicate we implement replicate_item/3; and
do this for every element, and concatenate the result in a prdicate named replicate/3.
#joel76 already provided a nice implementation for replicate_item/3. I will only change the order of the parameters:
replicate_item(N, X, List) :-
length(List, N),
maplist(=(X), List).
Now our replicate/3 prdicate can iterate over the list, and for each element use replicate_item/3 to generate a sublist. We can then use append/2 [swi-doc] for this:
replicate(LA, N, List) :-
maplist(replicate_item(N), LA, LL),
append(LL, List).

check if element is repeated in list in prolog

multi_available(X):-
member(X,
[grilled_chicken,
jambo_beef,
grilled_cheese_sandwich,roast_beef,potato_salad,chicken_rice,
jambo_beef,
service_dish,service_dish,
beef_stew,potato_corn,grilled_chicken,roast_beef,mushroom_rice,
service_dish,
jambo_beef]).
member(X,[X|_]).
member(X,[_|T]):-member(X,T).
How can I check if an element is repeated in a list in Prolog?
Using Prologue of Prolog:
member(X, L) is true if X is an element of the list L.
select(X, Xs, Ys) is true if X is an element of the
list Xs and Ys is the list Xs with one occurrence of X removed.
I get the following simple solution:
:- use_module(library(basic/lists)).
multi_available(L, X) :- select(X, L, R), member(X, R).
It might not be the most efficient. But it works:
Jekejeke Prolog 2, Runtime Library 1.2.5
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- multi_available([a,b,c,b,a,d],X).
X = a ;
X = b ;
X = b ;
X = a ;
No
I'm not sure if you just want to know whether an element occurs more than once or whether you need how many times it occurs, so here's both!
See if the List contains Element, +1 to Count for every occurrence
occurrences(Element,[Head|Tail], Count, OutputCount) :-
Element = Head,
NewCount is Count + 1,
occurrences(Element, Tail, NewCount, OutputCount).
Element does not match the first element of the List? Don't add 1, go to the next element.
occurrences(Element, [Head|Tail], Count, OutputCount) :-
Element \= Head,
occurrences(Element, Tail, Count, OutputCount).
If the List is empty, return the final count
occurrences(Element,[],Count,Count).
Since the Count can't be negative, just pass it on as Zero and only return the result.
occurrences(Element, List, Count) :- occurrences(Element, List, 0, Count).
Check whether the result is higher than 1
moreThanOnce(Element, List) :-
occurrences(Element, List, Count),
Count > 1.
Does Element occur more than once in List?
?- moreThanOnce(1, [1,2,3,1,1,1]).
How many times does it occur?
?- occurrences(1, [1,2,3,1,1,1], Count).
Note that if a list is empty, [Head|Tail] will automatically fail and List = [] automatically succeeds. This means that OutputCount remains empty throughout the program, UNTIL the end condition is met, which is only reached after [Head|Tail] fails, meaning the list is empty. I hope this is clear enough, be sure to ask for clarifications if it isn't.

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. :)

Why prolog outputs a weird tree-like list?

In this Prolog code I intend to list the first N primes,
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
And it works fine if I want the list ordered backwards:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
But if I change the last line of the code from [P|L] to [L|P] like this:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
I get:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
What am I missing? This is driving me mad!
Recall that a list is either the empty list [] or a term with functor '.' and two arguments, whose second argument is a list. The syntax [P|Ps] is shorthand notation for the term '.'(P, Ps), which is a list if Ps is a list (as is the case in your example). The term '.'(Ps, P), on the other hand, which can also be written as [Ps|P] (as you are doing), is not a list if P is not a list. You can obtain a reverse list with reverse/2.
Great, so you've discovered the problem of adding elements to the end of a list. In Prolog, we can do it with
add(X,L,Z):- L=[X|Z].
wait, what? How to read this? We must know the calling convention here. We expect L and Z to come in as uninstantiated variables, and we arrange for L from now on to point to a newly created cons node with X at its head, and Z its tail. Z to be instantiated, possibly, in some future call.
IOW what we create here is an open-ended list, L = [X|Z] = [X, ...]:
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,Z,L) :- N > 0, % make it explicitly mutually-exclusive,
N1 is N-1, % do not rely on red cuts which are easily
biggerPrime(A,P), % invalidated if clauses are re-arranged!
A1 is P+1,
L = [P|R], % make L be a new, open-ended node, holding P
primeListAcc(N1,A1,Z,R). % R, the tail of L, to be instantiated further
primeListAcc(0,A,R,R). % keep the predicate's clauses together
We can see now that Z is not really needed here, as it carries the [] down the chain of recursive calls, unchanged. So we can re-write primeListAcc without the Z argument, so that its final clause will be
primeListAcc(0,A,R):- R=[].
Keeping Z around as uninstantiated variable allows for it to be later instantiated possibly with a non-empty list as well (of course, only once (unless backtracking occurs)). This forms the basis of "difference list" technique.
To answer your literal question - here, consider this interaction transcript:
1 ?- X=[a|b].
X = [a|b]
2 ?- X=[a|b], Y=[X|c].
X = [a|b]
Y = [[a|b]|c]
the [a|b] output is just how a cons node gets printed, when its tail (here, b) is not a list. Atoms, as numbers, are not lists.

adding element into the List with 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].

Resources