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.
Related
I need a function that will do this:
Odd Length list
Input '(1 2 3 4 5) = '(1 (2 (3) 4) 5)
Even length list
Input '(1 2 3 4) = '(1 (2 () 3) 4)
It needs to use very minimal built in functions. I have spent hours trying to figure this out and I am completely out of ideas at this point.
Here is what I have:
(define (listInList L)
(define length (listLength L))
(define L2 (listInListHelper length L '() '()))
(define L3 (listInListHelper (- length 2) L L2 '()))
L3
)
(define (listInListHelper N L NL)
(cond
((= N 0) '()
((= N 1) (cons (list (car L)) NL))
(else (cons (cons (car L) (list (lastItem L))) NL)
(remove 1 L)))
)
)
(define (lastItem L)
(if (null? (cdr L))(car L)
(lastItem (cdr L)))
)
(define (remove N L)
(cond ((eq? N 0) (cdr L))
(else (cons (car L) (remove (- N 1)(cdr L))))))
This would be one way to do it, you need to tell me if it's minimal enough:
(define (f lst)
(define (helper lst rlst half)
(cond
((= half 0 ) null)
((= half 1/2) (list (car lst)))
(else (list (car lst)
(helper (cdr lst) (cdr rlst) (sub1 half))
(car rlst)))))
(helper lst (reverse lst) (/ (length lst) 2)))
testing:
> (f '(1 2 3 4 5))
'(1 (2 (3) 4) 5)
> (f '(1 2 3 4))
'(1 (2 () 3) 4)
I am currently trying to write a function that gives me a list with the position numbers of the position that contains the element 1 as elements.
Unfortunately, when I execute the following function it gives me '()which is the initial value of lst.
So I am not sure what to write for the case (< pos 0).
(define lst '())
(define (posj pos) (if (< pos 0)
lst
(begin (cond ((equal? (list-ref l pos) 1) (begin (set! lst (append (list* pos) '()))
(posj (- pos 1))))
(else (posj (- pos 1)))))))
(define l '(1 3 1 2 1 5 1))
(posj (- (length l) 1))
What you probably meant to write was this, with list instead of list*, lst instead of '(): (and with more standard indentation)
(define lst '())
(define (posj pos)
(if (< pos 0)
lst
(cond [(equal? (list-ref l pos) 1)
(begin
(set! lst (append (list pos) lst))
(posj (- pos 1)))]
[else
(posj (- pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj (- (length l) 1))
That works, but it relies on global variables (l and lst), which isn't a very good way of doing things. Then you can translate that from global variables into function arguments. The (set! lst (append ...)) can be replaced by passing the (append ...) as an argument:
(define (posj l lst pos)
(if (< pos 0)
lst
(cond [(equal? (list-ref l pos) 1)
(posj l (append (list pos) lst) (- pos 1))]
[else
(posj l lst (- pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj l '() (- (length l) 1))
So far l has just been the same list every time, when the part that you actually need shrinks every time. To fix that, you can iterate from front-to-back instead of back-front, and use first and rest in the recursion. Also the order of the arguments to append has to be switched because we're iterating in the other direction now, and the (< pos 0) check can be replaced by an (empty? l) check:
(define (posj l lst pos)
(if (empty? l)
lst
(cond [(equal? (first l) 1)
(posj (rest l) (append lst (list pos)) (+ pos 1))]
[else
(posj (rest l) lst (+ pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj l '() 0)
Now instead of using append it's much more efficient if you can use cons instead. That reverses lst, so rename it to rev-lst, and when you return it, reverse it again:
(define (posj l rev-lst pos)
(if (empty? l)
(reverse rev-lst)
(cond [(equal? (first l) 1)
(posj (rest l) (cons pos rev-lst) (+ pos 1))]
[else
(posj (rest l) rev-lst (+ pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj l '() 0)
Now it's starting to look a lot like the template for list functions, especially if you replace that if with a cond. Also, if you wanted to avoid passing '() and 0 as extra arguments, you could use either a helper function or a named let.
Your code doesn't work (append expects only lists) and is not the way to do it in Scheme for more than one reason.
I would suggest using a named let (classic Scheme):
(define (posj lst val)
(let loop ((lst lst) (pos 0) (res null))
(if (null? lst)
(reverse res)
(loop (cdr lst)
(add1 pos)
(if (= (car lst) val) (cons pos res) res)))))
or the more "rackety"
(define (posj lst val)
(reverse
(for/fold ((res null)) (((elt pos) (in-indexed lst)))
(if (= elt val) (cons pos res) res))))
then
> (posj '(1 3 1 2 1 5 1) 1)
'(0 2 4 6)
Since you're using Racket and presumably Dr Racket (the IDE),
use the automatic indentation feature, it helps a lot to make your code readable
in order to understand how this code works, use the build-in debugger to execute it step by step
read a Scheme tutorial which will teach you the common looping constructs, among other useful things.
I am currently confused with the idea behind functional programming in general. I currently have a working solution to my problem (That is, finding the min and max of a list, and returning these in a new list) but to do that, my solution essentially requires 3 functions, and this bothers me, because I am sure there is a way to do it with just 1 function in scheme.
So.. my question is, how do I combine the outputs of 2 functions into 1 concise function? (The driver function)
Here is what I have...
(define (findMax lst) ; Find and return maximum number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (drop-right lst 1))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMax (cdr lst))]
(else
(findMax (cdr lst))
)
)
)
(define (findMin lst) ; Find and return smallest number in a list
(cond [(null? lst) '()]
[(= (length lst) 1) (list-ref lst 0)]
[(> (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (cdr lst))]
[(< (list-ref lst 0) (list-ref lst (- (length lst) 1))) (findMin (drop-right lst 1))]
(else
(findMin (cdr lst))
)
)
)
I use a driver function to take both of these functions, and make a new list shown here:
(define (findEnds lst)
(list (findMin lst) (findMax lst))
)
So essentially, if given a list:
(6 7 8 4 9 2)
the output would be:
(2 9)
I know there is some way to use lambda possibly to do all of this in 1 function, but I need to be pointed in the right direction. Thanks!
Here's my version (note that I've changed it to return the result as a single dotted pair, rather than a list with two elements†):
(define (min/max lst)
(if (empty? lst)
#f
(let ((next (min/max (cdr lst))))
(define cur (car lst))
(if (not next)
(cons cur cur)
(cons (min (car next) cur) (max (cdr next) cur))))))
Example:
> (min/max '(3 1 4 1 5 9))
(1 . 9)
† If you really want to use a list of two elements, change all the cons to list, and change the (cdr next) to (cadr next).
This is actually a really good challenge that might help with learning some Scheme concepts. I've implemented min/max using fold-left. It might also be fun using a named-let
(define (min/max lst)
(fold-left
(lambda (acc num)
(cons (min num (car acc)) (max num (cdr acc))))
(cons +inf.0 -inf.0)
lst))
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)