Reputation: 383
I want to check if elements of list L1 occur consecutively, and in the same order, in list L2.
For example - check([b,c],[a,b,c,d]) must return true while check([b,d],[a,b,c,d]) must return false
I looked at similar posts Prolog - first list is sublist of second list? and also tried out similar solutions but whenever i try to check if elements are present, i am unable to check if ordering is consecutive
check( [], _ ).
check( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
check( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).
and if i try to check if ordering is correct then my code is breaking.
check( [], _ ).
check( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
Upvotes: 3
Views: 1667
Reputation: 18663
An alternative solution using the de facto standard definition of the append/3
predicate:
check(SubList, List) :-
append(Prefix, _, List),
append(_, SubList, Prefix).
Sample calls:
| ?- check([b,d],[a,b,c,d]).
no
| ?- check([b,c],[a,b,c,d]).
true ? ;
no
| ?- check([b,c],[a,b,c,d,b,c,f]).
true ? ;
true ? ;
no
We can also use this definition to generate sublist-list pairs:
| ?- check(SubList, List).
SubList = [] ? ;
List = [A|_]
SubList = [A] ? ;
List = [_|_]
SubList = [] ? ;
List = [A,B|_]
SubList = [A,B] ? ;
List = [_,A|_]
SubList = [A] ? ;
List = [_,_|_]
SubList = [] ? ;
List = [A,B,C|_]
SubList = [A,B,C] ? ;
List = [_,A,B|_]
SubList = [A,B] ? ;
...
This problem also gives you the opportunity to learn about termination properties of predicates. As an experiment, exchange the order of the append/3
calls and then check what happens on backtracking for e.g. the two first sample calls.
Upvotes: 3
Reputation: 476554
We can make use of append/2
[swi-doc] to write this with a one-liner:
subsequence(X, Y) :-
append([_,X,_], Y).
or we can implement a subsequence/4
that will unify two variables Prefix
and Suffix
with the list before and after the subsequence:
subsequence(X, Y, Prefix, Suffix) :-
append([Prefix,X,Suffix], Y).
Here we thus have two don't care variables that will collect the prefix and suffix before and after the subsequence.
Upvotes: 3
Reputation: 22803
Interesting problem! I'm surprised at how much code it took, so there may be a better solution than this.
First we need a helper to insist that a list is a prefix of another list. The base case is that we ran out of a prefix list; the inductive case is that the current items match and the remainder of both lists is a prefix match.
prefix([X|Xs], [X|Ys]) :- prefix(Xs, Ys).
prefix([], _).
Now finding a consecutive sublist amounts to searching down a list for prefix matches. If the current items match, then having a prefix is a match:
consecutive_sublist([X|Xs], [X|Ys]) :- prefix(Xs, Ys).
Otherwise, we just discard this element of the search target and try again on the sublist:
consecutive_sublist(Prefix, [_|Ys]) :- consecutive_sublist(Prefix, Ys).
Upvotes: 5