Search code examples
listprologclpfd

How to check different between two list integers are greater than or equal to 2?


Given two sorted lists Xs and Ys, how do I ensure the absolute difference between any X in Xs and any Y in Ys is at least two?

Sample queries with expected answers:

?- different([1,2,4],[5,6]).   % 5-4 < 2
false
?- different([1,4],[2,6]).     % 2-1 < 2
false
?- different([1,2,6],[4,8]).   % 4-2 >= 2 and 6-4 >= 2 and 8-6 >= 2
true
?- different([],[4]). 
true

How can I get to this result? Any ideas? Thank you!

Edit: Here is the code I have now:

difference([], []).
difference([_|_], []).
difference([], [_|_]).
difference(L1, L2) :-
   L1 = [X1|X2],
   L2 = [Y1|_],
   Dif is X1-Y1,
   (-1>Dif|Dif>1),
   difference(X2, L2).

Solution

  • First, you can make your current code a lot neater and easier to read as follows:

    different([], []).
    different([_|_], []).
    different([], [_|_]).
    different([X|Xs], [Y|Ys]) :-
        abs(X-Y) >= 2,     % Prolog evaluates arithmetic expressions for compares
        different(Xs, [Y|Ys]).
    

    In this case, you've done one level of the recursion I mentioned in my comment, as it only checks each element of the first list against only the first element of the second. It ignores all the other elements of the second list. So you need to break it down further. You could make a helper predicate which compares each element of a list against a single value. Then have your main predicate call this helper predicate with each element of the other list. The main predicate would then look like:

    different([], []).
    different([], [_|_]).
    different([X|Xs], L) :-
        different_element(X, L),
        different(Xs, L).
    

    Then the helper predicate would be:

    % This predicate succeeds if the first argument has the desired difference
    % to each of the elements of the second argument (a list)
    %
    different_element(_, []).
    different_element(X, [Y|Ys]) :-
        abs(X-Y) >= 2,
        different_element(X, Ys).