Deleting items from the list above / below a certain value

advertisements

I have written a small Prolog script which, taken a list, removes all values below a threshold N:

rem_under([], []).
rem_under([X|Xs], [X|Ys]) :-
    X >= 10,
    rem_under(Xs, Ys).
rem_under([X|Xs], Ys) :-
    X < 10,
    rem_under(Xs, Ys).

So, for example:

2 ?- rem_under([2,15,16,3,5,19],L).
L = [15, 16, 19]

I then wanted to make a similar function which removed all elements ABOVE a threshold N:

rem_over([], []).
rem_over([X|Xs], [Ys]) :-
    X > 10,
    rem_over(Xs, Ys).
rem_over([X|Xs], [X|Ys]) :-
    X <= 10,
    rem_over(Xs, Ys).

Which however returns:

1 ?- rem_over([2,15,17,6],L).
false.

Any idea why this is? Other than a few cosmetic changes, I have only swapped the < and > signs.


Your second clause is incorrect, because its second argument is [Ys] — a list of length 1:

rem_over( [X|Xs] , [Ys] ) :-
X > 10,
rem_over(Xs, Ys).

Once you've decided the head of the source list is greater than 10, you recurse down on the tail of the source list and the the contents of the result list.

Try this:

rem_over( []     , [] ) .      % source list exhausted? success!
rem_over( [X|Xs] , Ys ) :-     % source list non-empty?
  X > 10,                      % - head greater than the threshold?
  rem_over(Xs, Ys)             % - chuck it and recurse down on the remainder of the source list
  .                            %
rem_over( [X|Xs] , [X|Ys] ) :- % source list non-empty? add the head to the result
  X =< 10,                     % - IF it's less than or equal to the threshold
rem_over(Xs, Ys).              % - then recurse down on the remainder

Another way to get there:

rem_over( []     , [] ) .
rem_over( [X|Xs] , Ys ) :-
  ( X > 10 -> Y1 = Ys ; Y1 = [X|Ys] ) ,
  rem_over(Xs,Y1)
  .