Home > other >  Prolog. How to return a list of integers between a range
Prolog. How to return a list of integers between a range

Time:03-19

I want to return a list of integers given an input: rList :- (X,Y,[]) (1,4, N) returns N= [1,2,3,4]. This also needs to work for negative integers and for the other way around such that the input (4,-2, N) returns N= [4,3,2,1,0,-1,-2].

So far i have programmed the beginning, but I am stuck. Can someone explain to me how I should continue?

rList(_ , _ ,[ ]).

rList(X, Y, [X|T]) :-

must_be(integer, X),
must_be(integer, Y),
X =< Y,
N is X   1,
rList(N,Y,T).

this returns for: rList(1,4,N) N= [], [1], [1,2], [1,2,3], [1,2,3,4], false. Also all those first steps should not be given back as a result. I just need the last list ([1,2,3,4]) as an output.

Any tips/help would be appreciated.

thanks

CodePudding user response:

A possible solution is:

range(Start, Stop, List) :-
    must_be(integer, Start),
    must_be(integer, Stop),
    findall(X, elem(Start,Stop,X), List).

elem(Start, Stop, Element) :-
    Step is sign(Stop-Start),
    N is abs(Stop-Start),
    between(0, N, I),
    Element is Start   I*Step.

Examples:

?- range(1, 4, L).
L = [1, 2, 3, 4].

?- range(4, 1, L).
L = [4, 3, 2, 1].

?- range(-3, 3, L).
L = [-3, -2, -1, 0, 1, 2, 3].

?- range(5, 5, L).
L = [5].

?- range(5, 5, []).
false.

?- range(5, 6, [5, 6]).
true.

?- range(-5, -1, L).
L = [-5, -4, -3, -2, -1].

?- range(-1, -5, L).
L = [-1, -2, -3, -4, -5].

CodePudding user response:

Solution 1 (common solution):

?- findall(X, between(-2,4,X) , L).
L = [-2,-1,0,1,2,3,4].

Solution 2 (implement built-in between):

my_between(L, U, X) :-
  L =< U, !,
  (   X = L 
  ;   L1 is L   1,
      my_between(L1, U, X) ).

?- my_between(-2,4,X).
X = -2 ;
X = -1 ;
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
false.;

Solution 3 (follow your solution):

rList(X, Y ,[]) :- X > Y, !.
rList(X, Y, [X|T]) :-
  N is X   1,
  rList(N,Y,T).

?- rList(-2, 4, L).
L = [-2,-1,0,1,2,3,4].

?- rList(4, 4, L).
L = [4].

?- rList(5, 4, L).
L = [].

--- Edit ---

Thanks @slago, I didn't notice the two-way requirement, but it can be easily implemented:

my_between2(U, L, X) :-
  L =< U, !,
  (   X = U 
  ;   U1 is U - 1,
      my_between2(U1, L, X) ).


bi_between(L, U, X) :- L =< U, !, my_between(L, U, X).
bi_between(U, L, X) :- my_between2(U, L, X).

?- findall(X, bi_between(-2,4,X) , L).
L = [-2,-1,0,1,2,3,4].

?- findall(X, bi_between(4,-2,X) , L).
L = [4,3,2,1,0,-1,-2].

Also, for rList:

bi_rList(X, Y ,L) :- X =< Y, !, rList(X,Y,L).
bi_rList(X, Y, L) :- rList(Y,X,L1), reverse(L1,L).

?- bi_rList(-2, 4, L).
L = [-2,-1,0,1,2,3,4].

?- bi_rList(4, -2, L).
L = [4,3,2,1,0,-1,-2].

CodePudding user response:

Just a simple

range(B,B,[B]).
range(A,B,[A|Ns]) :- A < B , A1 is A 1, range(A1,B,Ns) .
range(A,B,[A|Ns]) :- A > B , A1 is A-1, range(A1,B,Ns) .

should do the trick. If you need to guard it, a simple decorator will do:

range( A , B , Ns ) :- integer(A), integer(B), range_(A,B,Ns) .

range_( B , B , [B]    ) .
range_( A , B , [A|Ns] ) :- A < B , A1 is A 1, range_(A1,B,Ns) .
range_( A , B , [A|Ns] ) :- A > B , A1 is A-1, range_(A1,B,Ns) .
  • Related