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