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.
Related
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)))))))
Problem:
Write a function (split l) that takes a list and partitions it into two equal-sized (within one) lists, and returns a pair whose car is the first list and whose cdr is the second list.
My code:
(define split list)
(let ((half (/ (length list) 2)
(cons (car half list)
(cdr half list))))
Here's another possible implementation using the tortoise and hare algorithm:
(define (split lst)
(let loop ((tortoise lst) (hare lst) (acc '()))
(if (or (null? hare) (null? (cdr hare)))
(cons (reverse acc) tortoise)
(loop (cdr tortoise)
(cddr hare)
(cons (car tortoise) acc)))))
The above solution has the advantage of traversing the list only once, notice that we don't need to know the length of the list to make the split. It's called "tortoise and hare" because we keep two pointers over the list: one advances slowly, one element at a time (the "tortoise") and the other goes faster, two elements at a time (the "hare"). The algorithm stops when the hare reaches the end of the input list.
Alternatively, we can implement a more idiomatic (albeit slower) solution using built-in procedures. Assuming that the take and drop procedures are available in your interpreter (if not, import them from SRFI-1), this is closer to what you had in mind:
(define (split lst)
(let ((half (quotient (length lst) 2)))
(cons (take lst half)
(drop lst half))))
Either way, it works as expected:
(split '(1 2 3 4))
=> ((1 2) 3 4)
(split '(1 2 3 4 5))
=> ((1 2) 3 4 5)
Try:
(define (splitAt n lst)
(let loop ((acc '()) (n n) (lst lst))
(if (or (= n 0) (null? lst)) (cons (reverse acc) lst)
(loop (cons (car lst) acc) (- n 1) (cdr lst)))))
(define (split lst) (splitAt (quotient (length lst) 2) lst))
It works as follows:
(split '(1 2 3 4)) => ((1 2) 3 4)
(split '(1 2 3 4 5)) => ((1 2) 3 4 5)
Hope this helps.
I would like to write a Racket function that takes a list and returns the position of the smallest element of that list. I already wrote a function that works:
(define (min-position xs)
(define (min-position2 count pos xs)
(cond ((null? xs) #f)
((= 1 (length xs)) pos)
((< (car xs) (cadr xs))
(min-position2 (+ count 1) pos (cons (car xs) (cddr xs))))
(else (min-position2 0 (+ count pos 1) (cons (cadr xs) (cddr xs))))))
(min-position2 0 0 xs))
Example inputs and outputs:
> (min-position '(9 8 7 6 5))
4
> (min-position '(9 8 1 6 5))
2
> (min-position '(0 1 2))
0
But is there a more elegant way to write this?
I'm not sure what you mean by "elegant". There may be a spiffier algorithm, for example. But here's how I would make the code more readable (IMHO) while retaining your basic approach.
Step by step:
Your input/ouput examples, rewritten as check-equal? tests:
#lang racket
(require rackunit)
(define (test f)
(check-equal? (f '(9 8 7 6 5)) 4)
(check-equal? (f '(9 8 1 6 5)) 2)
(check-equal? (f '(0 1)) 0)
(check-equal? (f '(0 1 2)) 0))
Your original, but using [] instead of () for cond clauses.
(define (min-position/v0 xs)
(define (min-position2 count pos xs)
(cond [(null? xs) #f]
[(= 1 (length xs)) pos]
[(< (car xs) (cadr xs))
(min-position2 (+ count 1) pos (cons (car xs) (cddr xs)))]
[else
(min-position2 0 (+ count pos 1) (cons (cadr xs) (cddr xs)))]))
(min-position2 0 0 xs))
(test min-position/v0)
Using match to destructure the list and use names like this and next instead of (car xs) and (cadr xs):
(define (min-position/match xs)
(define (min-position2 count pos xs)
(match xs
[(list) #f]
[(list _) pos]
[(list this next more ...)
(cond [(< this next)
(min-position2 (+ count 1) pos (cons this more))]
[else
(min-position2 0 (+ count pos 1) (cons next more))])]))
(min-position2 0 0 xs))
(test min-position/match)
Changing the internal function to a let loop .... Really the same thing, just a bit more concise.
(define (min-position/match&loop xs)
(let loop ([count 0] [pos 0] [xs xs])
(match xs
[(list) #f]
[(list _) pos]
[(list this next more ...)
(cond [(< this next) (loop (+ count 1) pos (cons this more))]
[else (loop 0 (+ count pos 1) (cons next more))])])))
(test min-position/match&loop)
Again, this is the same algorithm as your original. But I would find it easier to grok quickly.
Well, it all depends on your definition of elegant. For me, an elegant solution is one that is short, clear, idiomatic and uses existing procedures (that is, it doesn't reinvent the wheel). Here's my shot:
(require srfi/1) ; import `list-index`
(require srfi/26) ; import `cute`
(define (min-position lst)
(and (not (null? lst))
(list-index (cute = (apply min lst) <>) lst)))
Here's how it works:
(apply min lst) finds the minimum element in the list, using the built-in min procedure
(cute = (apply min lst) <>) uses cute for creating a specialized predicate that will return #t whenever an element is equal to the minimum, making sure that we find the minimum only once
(list-index (cute = (apply min lst) <>) lst) uses list-index with the previous predicate to find the index with the first minimum element in the list
The (and (not (null? lst)) … ) part is there for handling the edge case where the input list is empty
Short and sweet. The only disadvantage is that it traverses the input list twice, once for finding the minimum element and once again for finding the index of that element. But that's a small price to pay, and it's still an O(n) solution that works as expected:
(min-position '(9 8 7 6 5))
=> 4
(min-position '(9 8 1 6 5))
=> 2
(min-position '(0 1 2))
=> 0
(min-position '())
=> #f
A named let is a common idiom in Scheme:
(define (min-position xs)
(let loop ((xs xs) (pos 0) (mn #f) (mnpos #f))
(if (null? xs)
mnpos
(let ((c (car xs)))
(if (or (not mn) (< c mn))
(loop (cdr xs) (add1 pos) c pos)
(loop (cdr xs) (add1 pos) mn mnpos))))))
In Racket, you also have for/fold and in-indexed to make the code even shorter:
(define (min-position xs)
(define-values (mn mnpos)
(for/fold ((mn #f) (mnpos #f)) (((c pos) (in-indexed xs)))
(if (or (not mn) (< c mn))
(values c pos)
(values mn mnpos))))
mnpos)
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 new to scheme and am having some trouble debugging my code.
; returns number of elements in a list
(define (length L)
(cond ((null? L) 0)
(else (+ (length (cdr L)) 1))))
; split the list in half:
; returns ((first half)(second half))
(define (split L)
(cond
((= (length L) 0) (list L L) )
((= (length L) 1) (list L '() ))
(else
(list (sublist L 1 (/ (length L) 2) 1)
(sublist L (+ (/ (length L) 2) 1) (length L) 1)))))
; extract elements start to end into a list
(define (sublist L start end counter)
(cond ((null? L) L)
((< counter start) (sublist (cdr L) start end (+ counter 1)))
((> counter end) '())
(else (cons (car L) (sublist (cdr L) start end (+ counter 1))))))
To me, this feels like it would split a single list into two sub lists. There may be an easier way to do this, and so I apologize if this seems cumbersome.
Anyway, the results:
Expected: (split '(1 2 3 4 5)) = ('(1 2) '(3 4 5))
Actual: (split '(1 2 3 4 5)) = ('(1 2) '(4 5))
It's clear that the length or split is losing the middle value, but I've checked it again and again and it seems to lose the middle value. It seems like an easy solution would be to get rid of the (+ 1) of (+ (/ (length L) 2) 1) but this seems counter intuitive to me, as:
Assume L = '(1 2 3 4 5), (/ (length L) 2) = 2, and (+ (/ (length L) 2) 1) = 3
(sublist L 1 (2) 1) = '(1 2)
(sublist L (3) 5 1) = '(3 4 5)
** I put parens around the 2 and 3 to indicate that they were length calculations.
Clearly an assumption I am making is false, or I am overlooking something trivial.
Thanks in advance!
Do you know the tortoise-and-hare algorithm? The tortoise walks the list, the hare runs the list at double speed. The split occurs at the position of the tortoise when the hare reaches the end of the list. Here's most of the code; I'll let you figure out the rest:
(define (split xs)
(let loop ((ts xs) (hs xs) (zs (list)))
(if (or (null? hs) (null? (cdr hs)))
(values (reverse zs) ts)
(loop ...))))
Here ts is the remaining list of items to be examined by the tortoise, hs is the remaining list of items to be examined by the hare, and zs is the list of items already examined by the tortoise, in reverse order.
Note that you never need to count the items in the input list.
I'm not going to debug your code for you. Instead, here's a simpler definition of split:
(define (split l)
(let ((n (length l)))
(list (take (/ n 2) l)
(drop (+ (/ n 2) (mod n 2)) l))))
Exercise for the reader: implement take and drop. The latter is just recursion on n while taking the cdr of l in the recursive case; the former takes slightly more effort to get right in the base case (stopping condition).
Here is almost your solution (Racket Scheme):
#lang racket
(define (length lst)
(cond [(empty? lst) 0]
[else (+ (length (rest lst)) 1)]))
(define (first-length lst)
(quotient (length lst) 2))
(define (second-length lst)
(- (length lst) (first-length lst)))
(define (sublist lst start end counter)
(cond [(empty? lst) lst]
[(< counter start) (sublist (rest lst) start end (+ counter 1))]
[(> counter end) '()]
[else (cons (first lst) (sublist (rest lst) start end (+ counter 1)))]))
(define (first-half-of-list lst)
(sublist lst 1 (first-length lst) 1))
(define (second-half-of-list lst)
(sublist lst (second-length lst) (length lst) 1))
(define (split lst)
(cond
[(= (length lst) 0) (list lst lst)]
[(= (length lst) 1) (list lst '())]
[else (list (first-half-of-list lst)
(second-half-of-list lst))]))
(split '(1 2 3 4 5))
=> '((1 2) (3 4 5))
Thank you for good brain exercise.
The key moment is 'second-length'-function.