I am trying to create a list of n elements. It must produce this output:
(my-list 5)
>> 0 1 2 3 4
I have the function below:
(define (my-list n)
(cond
((<= n 0) '())
(else (reverse-list (cons (- n 1)
(my-list(- n 1)))))
)
)
and this is producing
(my-list 10)
>>(8 6 4 2 0 1 3 5 7 9)
I understand this is due to reversing the list at every recursive call, but I am not sure what is the correct way. Also my reverse-list is working fine.
Thanks in advance!
A standard idiom in Scheme 'build-and-reverse' suggests you only reverse the list once, at the very end, when its reverse has been completely built (thus reducing the complexity down to O(N) from quadratic.)
So yes, you end up in a tail call to reverse but the list should be built without doing it. Scheme has plenty of local recursive binding constructs.
But.
If you build a range starting with the largest value (that should be one greater than the last element to the list) you don't need to reverse it in the end, at each iteration step you decrease a counter and prepend its new value to those already accumulated:
(define (range n)
(let rng ((m (- n 1)) (ret-val '())) ; named-let is very useful for small local recursive closures
(if (< m 0) ; that original (<= n 0) check is also handled here
ret-val ; here, the result is returned; note we don't need to reverse it
(rng (- m 1) (cons m ret-val))))))
(display (range 10))
(newline)
prints
(0 1 2 3 4 5 6 7 8 9)
Or, to demonstrate the build-and-reverse, we can start with the lowest value:
(define (range-asc n)
(let rng ((m 0) (ret-val '()))
(if (= m n)
(reverse ret-val) ; since we started from zero, we need to reverse it
(rng (+ m 1) (cons m ret-val)))))
(Looks like I still remember/can recover some Scheme. :-O)
First of all, your code. Properly formatted it should look something like:
(define (my-list n)
(cond ((<= n 0) '())
(else (reverse-list (cons (- n 1)
(my-list (- n 1)))))))
Problem you have, is reverse-list call. It happens every time you add new element to the list. You can fix it in many ways, but simple solution is to wrap your recursive code into local function, and do some additional operations (reverse in your case) when it returns.
(define (my-list n)
(define (build-list m)
(cond ((<= m 0) '())
(else (cons (- m 1)
(build-list (- m 1))))))
(reverse-list (build-list n)))
So, inside my-list function, first we define recursive part as a local function build-list. This is exactly your code, but with call to reverse-list removed. This part will build your list, but as you know, in reverse order. But that is no longer a problem, since we can reverse it when local function returns.
Related
****What I tried****
(define(help num)
(if(= num 1)
num
(cons(num (help( - num 1))))))
;i called this defination in the bottom one
(define (list-expand L)
(cond
[(empty? L)'()]
[(=(car L)1)(cons(car L)(list-expand (cdr L)))]
[(>(car L)1) (cons(help(car L)(list-expand(cdr L))))]))
In the help procedure, the base case is incorrect - if the output is a list then you must return a list. And in the recursive step, num is not a procedure, so it must not be surrounded by brackets:
(define (help num)
(if (<= num 0)
'()
(cons num (help (- num 1)))))
And in list-expand, both recursive steps are incorrect. You just need to test whether the list is empty or not, calling help with the correct number of parameters; use append to combine the results, because we're concatenating sublists together:
(define (list-expand L)
(if (empty? L)
'()
(append (help (car L)) (list-expand (cdr L)))))
That should work as expected, but please spend some time studying Scheme's syntax, you still have trouble with the basics, for instance, when and where to use brackets...
(list-expand '(3 2))
=> '(3 2 1 2 1)
Just for fun - a non-recursive solution in Racket:
(append-map (lambda (n) (stream->list (in-range n 0 -1))) '(3 2))
;; or:
(append-map (lambda (n) (for/list ((x (in-range n 0 -1))) x)) '(3 2))
Returning:
'(3 2 1 2 1)
I've been messing around with common LISP for a couple of weeks now, mostly attempting to practice recursion. What I want to do is to have a function
(defun rem (n l)
; code here
)
where n is always a non-negative integer and l can be an atom/list/null. The function removes the n-th element (one-based indexing) of:
the list (l) itself
any-level sub-lists that the original list contains
I reckon using remove and nth would make this task a piece of cake, but I've yet to have any success.
Any answers/actual code would be greatly appreciated. Thanks!
You didn't say if you wanted remove functionality or delete functionality. I'll do the non destructive versions here.
You can make remove-nth for one list by making a new list of all the elements before the index, then use the tail of the cons you want to remove to share as much structure as possible. Here is an implementation using subseq, nconc, and nthcdr to show how easy it is without recursion.
(defun remove-nth (n list)
(nconc (subseq list 0 n) (nthcdr (1+ n) list)))
(defparameter *test* (list 0 1 2 3 4 5 6))
(remove-nth 3 *test*) ; ==> (0 1 2 4 5 6)
(remove-nth 0 *test*) ; ==> (1 2 3 4 5 6)
A recursive function would look something like this:
(defun remove-nth-rec (n list)
(assert (not (null list)))
(if (zerop <??>)
<??>
(cons <??> (remove-nth-rec <??> <??>))))
You can make function that does this on each sublist recursively too. I'd do this with mapcar:
(defun remove-all-nth (n lol)
(mapcar (lambda (x) (remove-nth n x)) lol))
(remove-all-nth 0 '((a b c) (0 1 2) (I II III))) ; ==> ((b c) (1 2) (II III))
A recursive function would look something like this:
(defun remove-all-nth-rec (n list)
(if (null <??>)
nil
(cons (remove-nth-rec n <??>)
(remove-all-nth-rec n <??>))))
First off, scheme: return a lst that only contains the first element of the lst did not help much, as the question was never really answered, and I followed the contributor's suggestions to no success. Furthermore, I am approaching this with a do loop, and have almost achieved the solution.
I need to make a procedure that will return the first n items in a passed list. For example, (first-n 4 '(5 8 2 9 4 0 8 7)) should give (5 8 2 9).
Here is my approach, the display is there to make sure that the loop is working, which it is:
(define (front-n n list)
(do ((i 0 (+ i 1)))
((> i (- n 1)))
(display (list-ref list i))))
How do I go about making that return a list, or output a list?
Your do-loop, and #Penguino's recursive function, both fail if there are less than n items in the input list. Here is a simple version based on named-let, renamed take which is the normal name for this function:
(define (take n xs)
(let loop ((n n) (xs xs) (zs (list)))
(if (or (zero? n) (null? xs))
(reverse zs)
(loop (- n 1) (cdr xs)
(cons (car xs) zs)))))
Or, if you prefer the recursive function version:
(define (take n xs)
(if (or (zero? n) (null? xs))
(list)
(cons (car xs) (take (- n 1) (cdr xs)))))
The named-let version is preferable to the recursive version, because the recursion isn't in tail position, so it builds a large intermediate stack.
You said that you wanted a version using do. That's harder, because the test that terminates the loop is performed after the action of the loop, and you need to perform the test before the action. You can either test one-ahead, which is awkward, or use this loop that delays the action until after the test has succeeded:
(define (take n xs)
(let ((zs (list)))
(do ((n n (- n 1)) (xs xs (cdr xs)))
((or (zero? n) (null? xs)) (reverse zs))
(set! zs (cons (car xs) zs)))))
The set! isn't particularly Schemely, but at least it shares with the named-let version the property that it doesn't build an intermediate stack.
How about
(define (front-n n list)
(cond ((= 0 n) '())
(else (cons (car list) (front-n (- n 1) (cdr list))))))
with a little pseudo-error-trapping added.
Testing with:
(front-n 4 '(5 8 2 9 4 0 8 7))
(front-n 8 '(5 8 2 9 4 0 8 7))
produces the expected output:
'(5 8 2 9)
'(5 8 2 9 4 0 8 7)
>
Note that the error checking may be useful.
Here is a tail recursive version:
(define (take n a-list)
(define (iter counter result sublist)
(cond
[(empty? sublist) result]
[(< counter n)
(iter
(+ counter 1)
(append result (list (car sublist)))
(cdr sublist))]
[else result]))
(cond
[(= n 0) '()]
[else (iter 0 '() a-list)]))
It differs slightly from the library procedure, because the library procedure throws an error, if you give a take count which is larger than the length of the list, while this function returns the whole list in that case.
Note however, that it makes use of append. I could not figure out a way around that yet.
I'm trying to create a function that takes in user input, x, and displays all of the numbers from 1 up to x. Not quite sure where to go from here:
(define (iota x)
(if (>= x 1)
(display
;; Takes a number n
;; and returns a list with 1..n
;; in order.
(define (make-list n)
(let loop ((n n) (accumulator '()))
(if (zero? n)
accumulator
(loop (- n 1) (cons n accumulator)))))
;; prints data and adds
;; a newline
(define (println x)
(display x)
(newline))
;; prints 1..n by applying println
;; for-each element over the list 1..n
(define (iota n)
(for-each println (make-list n)))
Basically you want to use recursion. So think of it was counting up. As you count up either you've added enough numbers and you are done building your list or you need to add the current number to your list and go on to the next number.
Look at the following code:
(define (range-2 next-num max-num cur-list)
;;if we've added enough numbers return
(if (> next-num max-num)
cur-list
;; otherwise add the current number to the list and go onto the next one
(range-2
(+ 1 next-num)
max-num
(append cur-list (list next-num))
)))
But to get the function you wanted you need to start off with the constants you specified (ie 1), so lets create a convenience function for calling range with the starter values you need to set up the recursion, sometimes called priming the recursion:
(define (range X)
(range-2 1 X `() ))
You could do it without the second function using lambda, but this is pretty common style from what I've seen.
Once you've constructed a list of the numbers you need you just display it using
(display (range 10))
If you're using Racket you're in luck, you can use iterations and comprehensions, for instance in-range:
(define (iota x)
(for ([i (in-range 1 (add1 x))])
(printf "~a " i)))
Or for a more standard solution using explicit recursion - this should work in most interpreters:
(define (iota x)
(cond ((positive? x)
(iota (- x 1))
(display x)
(display " "))))
Either way, it works as expected:
(iota 10)
=> 1 2 3 4 5 6 7 8 9 10
(define iota2
(lambda (y)
(let loop ((n 1))
(if (<= n y)
(cons n (loop (+ n 1)))
'()))))
(define (iota x)
(if (>= x 1)
(begin
(iota (- x 1))
(display x)
(newline))))
Assume I have the list (3 1 4 5 2) with the name "numbers". I am looking for a command that will reverse the list from index 0 up to an arbitrary index, i.e. (reverse numbers 2) which will give the new list as (4 1 3 5 2).
I've tried googling, but could not find a suitable function and I'm too much of a newbie to write the function myself at this stage.
Thank you.
Simple CL version based on the libary functions:
(defun reverse-first-n (list n)
(nreconc (subseq list 0 n) (nthcdr n list)))
This is memory-optimal, i.e., it does not allocate unnecessarily:
no need to copy the tail, thus nthcdr instead of subseq
revappend copies the 1st argument which is a fresh list anyway, so nreconc is more economical.
This version is speed-suboptimal, because it traverses list to the nth position 3 times - once in subseq, once in nthcdr, and then once in nreconc.
Here is the optimal verion:
(defun reverse-first-n (list n)
(if (or (= n 0) (= n 1))
list
(do* ((tail (list (pop list)))
(head tail (cons (pop list) head))
(count (1- n) (1- count)))
((zerop count)
(setf (cdr tail) list)
head))))
Note that there is very little chance that this is the performance bottleneck in your code. My main purpose in providing the second version is to show how much time and effort the extensive and well-designed CL library saves you.
Which dialect of Lisp are you using? Here's a Scheme solution (using SRFI 1):
(require srfi/1) ; assuming you're using Racket
(define (reverse-first-n lst n)
(call-with-values (lambda ()
(split-at lst n))
append-reverse!))
I made the function really "reverse the first n elements" like your title says, and unlike your question description. So for example:
> (reverse-first-n '(3 1 4 5 2) 2)
'(1 3 4 5 2)
> (reverse-first-n '(3 1 4 5 2) 3)
'(4 1 3 5 2)
As requested by the OP, here's a Common Lisp version. sds already posted a pretty decent version, so the version I'm writing is a more direct port of my Scheme solution (append-reverse! ⇒ nreconc; call-with-values ⇒ multiple-value-call; and I'm porting SRFI 1's split-at to CL):
(defun split-at (list n)
(if (zerop n)
(values '() list)
(multiple-value-bind (prefix suffix)
(split-at (cdr list) (1- n))
(values (cons (car list) prefix) suffix))))
(defun reverse-first-n (list n)
(multiple-value-call #'nreconc (split-at list n)))
(Why split-at? Its purpose is to provide both the take (subseq) and drop (nthcdr) with only one traversal of the input list.)