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.
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 am quite new with Scheme and with StackOverflow as well!
So, for the first contact I would like to do something simple and easy in Scheme.
I want to define a function that substracts the elements of the introduced list.
For example, the inputs should be: (sub '(4 12 6) '(0 6 3))
And the output should be: (4 6 3)
Thanks!!
What you'll need is to have a base case where you check if either list is empty and evaluate it to the empty list or you make a pair with the calculation of the first element of each list and the recursion for the rest of both lists. Basically you end up with:
(cons (- 4 0) (cons (- 12 6) (cons (- 6 3) '()))) ; ==> (4 6 3)
As an example of a recursive list processing function here is one that negates all elements:
(define (negate-list lst)
(if (null? lst)
'()
(cons (- (car lst))
(negate-list (cdr lst)))))
(negate-list '(1 2 3 4)) ; ==> (-1 -2 -3 -4)
Now there are even more fancy ways to do this. Eg,. you can use tail recursion:
(define (negate-list lst)
(let loop ((lst lst) (acc '()))
(if (null? lst)
(reverse acc)
(loop (cdr lst)
(cons (- (car lst)) acc)))))
You can use map:
(define (negate-list lst)
(map - lst))
So there you go. you're half way there.
Trying to delete every nth item in scheme recursively
(define x '(1 2 3 4 5 6 7 8 15 10))
(define ndelete
(lambda (alist nth) ;#params (list to delete items from) (nth intervals to delete items)
(cond [(null? alist) alist] ;if null, return empty list
[(if (= nth 1) (ndelete (cdr alist) nth))]
[else (list (car alist) (ndelete (cdr alist) (- nth 1)))]
)))
when i call:
> (ndelete x 5)
the output should be:
(1 2 3 4 6 7 8 15)
but i get blank output:
> (ndelete x 5)
>
At the (= nth 1) condition, you skipped the element but did not reset the nth back up to 5 (or whatever the initial value was). That means it stayed at 1 and skipped every element afterwards.
To solve this, you will need an inner function that keeps a counter, while still letting you hold on to the initial n. Here's my solution (I chose to count up to n rather than down from n):
(define (ndelete lst n)
(let recur ((i 1)
(rest lst))
(cond ((null? rest) '())
((= i n) (recur 1 (cdr rest)))
(else (cons (car rest) (recur (+ i 1) (cdr rest)))))))
I was wondering, if I was given a list such as:
(list 3 6 9 2 1 0 5 9)
and I wanted to produce only the first 5. i.e.: I want to produce:
(list 3 6 9 2 1)
How could I go about doing this. By the way, recursion is not allowed, and the language is intermediate student. Thanks :)
Actually a lis like (1 2 3 4) is a chain of pairs (1 . (2 . (3 . (4 . ())))). You cannot reuse the pairs since you need the 5th pair to point to () (null) instead of the rest of the pair chain. The only way to do this is to make a new pair for each element you'd like by using the same car elements in each.
(define (take lst cnt)
(if (zero? cnt) ; if you ask for zero element
'() ; then return empty list
(cons (car lst) ; else make a pair with first element
(take (cdr lst) ; and result from take with the rest of the list
(- cnt 1))))) ; with one less element than you originally asked for
If memory serves, in addition to car and cdr, Scheme supplies caar, caaar, caaaar and the equivalent repeated ds and the various combinations and permutations. So one solution would be:
(define x (list 3 6 9 2 1 0 5 9))
(list (car x) (cadr x) (caddr x) (cadddr x) (car (cddddr x)))
(and I'm sure that's why you were asked for the first five; there's no cdddddr — the teaching point was likely the permitted repetition of ds and as and the limit to which you can go with those)
I do not know why you would want to do this, but one way to avoid recursion is to unroll the loop:
(define (take1 xs) (cons (car xs) '()))
(define (take2 xs)
(cons (car xs) (take1 (cdr xs))))
(define (take3 xs)
(cons (car xs) (take2 (cdr xs))))
(define (take4 xs)
(cons (car xs) (take3 (cdr xs))))
(define (take5 xs)
(cons (car xs) (take4 (cdr xs))))
Trying to learn lisp, want to delete every nth. I only managed to delete the first (nth) element
(defun delete-nth (n list)
(if (zerop n)
(cdr list)
(let ((cons (nthcdr (1- n) list)))
(if cons
(setf (cdr cons) (cddr cons))
cons))))
I'd like to delete the next nth and so on
Also I tried this:
(defun remove-nth (list n)
(remove-if (constantly t) list :start n :end (+ 1 n)))
No idea how to start again
What I was thinking was concatenating, but I have no idea of how to keep track of my position.
Counting from 1 (changing to 0 is trivial):
(defun remove-every-nth (n list)
(loop for element in list
for index from 1
unless (zerop (rem index n))
collect element))
Also: Please indent your code correctly.
An alternative way to do the same thing:
(defun remove-all-nth (list period)
(remove-if
(let ((iterator 0))
(lambda (x)
(declare (ignore x))
(= 0 (mod (incf iterator) period)))) list))
(remove-all-nth '(1 2 3 4 5 6 7 8 9 0) 3)
; (1 2 4 5 7 8 0)
Perhaps a more academic recursive solution here:
(defun delete-nth (n list)
(labels ((rec (i list)
(cond ((null list) nil)
((= i 1) (rec n (cdr list)))
(t (cons (car list) (rec (1- i) (cdr list)))))))
(rec n list)))
But in real life I'd use the loop option above.