scheme listing sucessive averages in reverse - list

I am trying to list sucessive averages of elements in a list in reverse, for example in a list of (1 2 3) i try to get (3+2+1/3 2+1/2 1) here is an example of a list i tried my code on.
(list 2 3 4 5 6)
For some reason the values returned are " (4 7/2 4 7/2 4)". This is the code
(define (sucessive-avg lst)
(if (=(length lst) 1)
lst
(cons(avg(reverse lst)) (sucessive-avg(cdr(reverse lst))))))
The problem does not come from my avg so i dont know what is wrong with it

How many times will you call reverse? Try to do a step-by-step execution of your code to understand what is going on.
You could write a function which collect averages for the successives CDRs of a list, and call it with a reversed list:
(define (successive-averages lst)
(if (null? lst)
lst
(cons (avg lst)
(successive-averages (rest lst))))
(successive-averages (reverse (list 2 3 4 5 6)))

#coredump's answer is a pretty good start but it doesn't use proper tail recursion and it looks like it's averaging the wrong parts of the list
for example in a list of (1 2 3) i try to get (3+2+1/3 2+1/2 1)
For a list of '(2 3 4 5 6) my answer will give you
'((avg '(2 3 4 5 6))
(avg '(2 3 4 5))
(avg '(2 3 4))
(avg '(2 3))
(avg '(2)))
This seems to match your description more accurately.
Here's the code
(define (avg lst)
(/ (foldl + 0 lst)
(length lst)))
(define (successive-avg lst)
(define (iter res lst)
(if (empty? lst)
(reverse res)
(iter (cons (avg lst) res) (rest lst))))
(iter '() (reverse lst)))
(print (successive-avg '(2 3 4 5 6)))
Output
'(4 3 1/2 3 2 1/2 2)

You don't actually need to recall reverse or average at all. The reason you don't need average is that you can keep a running sum (in my code via a lambda chain) and an explicit count. And sense you want the result of the deepest recursion first, consing running average onto an acumulator as you recure gives you the right final order.
(define (successiveAvg Lst)
(cond ((null? Lst)
(error "succesiveAvg requires a non-empty list"))
((fold (lambda (acc x)
(if acc (number? x) #f))
#t
Lst)
(error "succesiveAvg requires a list of numbers" Lst))
(else
(let ((inc (lambda (x)
(+ 1 x)))
(f (lambda (x)
(lambda (y) (+ x y)))))
(let loop ((acc '())
(c (lambda (x) x))
(L lst)
(i 1))
(if (null? L)
acc
(loop (cons (/ (c (car L)) i)
acc)
(f (c (car L)))
(cdr L)
(inc i))))))))
(successiveavg '(2 3 4 5 6))
;Value 3: (4 7/2 3 5/2 2)

Related

Racket Scheme Deleting elemts of list in range

How can I delete the values of list in range(a, b)? I tried with:
#lang racket
(define (remove L i n)
(cond ((null? L)
empty)
((> i 0)
(cons (car L) (remove (cdr L) (sub1 i) n)))
((> n 0)
(remove (cdr L) i (sub1 n)))
(else
L)))
But the result is:
(remove '(1 2 3 4 5) 2 4)
'(1 2)
(remove '(1 2 3 4 5 6 7 8 9) 2 5)
'(1 2 8 9)
I would like to have:
(remove '(1 2 3 4 5) 2 4)
'(1 5)
I think this will be easier to implement if you keep another parameter with the current index:
(define (remove L index start end)
(cond ((null? L)
empty)
((and (>= index start) (<= index end))
(remove (cdr L) (add1 index) start end))
(else
(cons (car L) (remove (cdr L) (add1 index) start end)))))
If you don't want to add one extra parameter, we can always use a named let:
(define (remove L start end)
(let loop ((lst L) (index 1))
(cond ((null? lst)
empty)
((and (>= index start) (<= index end))
(loop (cdr lst) (add1 index)))
(else
(cons (car lst) (loop (cdr lst) (add1 index)))))))
Either way, it works as expected:
(remove '(1 2 3 4 5) 2 4)
=> '(1 5)
(remove '(1 2 3 4 5 6 7 8 9) 2 5)
=> '(1 6 7 8 9)
There are two bugs:
You're using one-based indexing, so the first condition should be (> i 1);
Since the list shrinks in the first recursive clause, you need (sub1 n) there, too.
Passing n makes it count how many elements to remove rather than the index of where to stop.

Make a function in Scheme to substract two lists

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.

Scheme - Splitting a list into two equal lists

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.

Duplicate every found element in a list in Scheme

I want to duplicate every found element in a list. I have the idea but i can't make it right. Sample input is >(pass '(1 2 3 4 4)) will have the output (1 1 2 2 3 3 4 4 4 4). Anyone out there help me. Here is my code ..
(define duplicate
(lambda (mylist n)
(cond ((null? mylist) "Not found")
((< n 2) (cons (car mylist)
(duplicate mylist (+ n 1))))
(else
(duplicate (cdr mylist) 0)))))
(define pass
(lambda (mylist)
(duplicate list 0)))
I will appreaciate all valuable comments.
Just a couple of fixes (see the comments) and we're good to go:
(define duplicate
(lambda (mylist n)
(cond ((null? mylist) '()) ; base case must return the empty list
((< n 2) (cons (car mylist)
(duplicate mylist (+ n 1))))
(else
(duplicate (cdr mylist) 0)))))
(define pass
(lambda (mylist)
(duplicate mylist 0))) ; pass myList, not list
Notice that the procedure can be simplified a bit:
(define (pass lst)
(if (null? lst)
'()
(cons (car lst)
(cons (car lst)
(pass (cdr lst))))))
Or even better, using higher-order procedures for a more idiomatic solution:
(define (pass lst)
(foldr (lambda (ele acc) (list* ele ele acc))
'()
lst))
Yet another alternative:
(define (pass lst)
(append-map (lambda (ele) (list ele ele))
lst))
Anyway, it works as expected:
(pass '(1 2 3 4 4))
=> (1 1 2 2 3 3 4 4 4 4)
I would do it so:
(define (dup l)
(define (iter l co)
(if (null? l)
(co '())
(iter (cdr l)
(lambda (x)
(co (cons (car l) (cons (car l) x)))))))
(iter l (lambda (x) x)))
(dup '(1 2 3))
It may be simpler to treat duplicate as zipping a list with itself. Then flattening the resulting list.
In Scheme or Racket:
(require srfi/1)
(define (duplicate-list-members lox)
(flatten (zip lox lox)))
Though it runs in O(n) time, profiling may indicate that passing through the list twice is a bottleneck and justify rewriting the function. Or it might not.
Try using map and list
(define (duplicate my-list)
(flatten
(map
(lambda (x)
(list x x))
my-list)))`
Gives requested format:
> (duplicate (list 1 2 3 4 4))
'(1 1 2 2 3 3 4 4 4 4)

Sorting a list of sublists in scheme

IN SCHEME
I am trying to write a section of code to sort a list of sublists, using the difference between to elements of each sublist. What i mean is:
ie.,
list of sublists: '('(ted 10 4) '(barbie 10 5) '(car 10 7) '(ball 10 6))
and i want to sort the list based on the difference between the 2nd and 3rd element of each sublist list thus the sorted list should look like in ascending order (lowest to highest):
'('(car 10 7) '(ball 10 6) '(barbie 10 5) '(teddy 10 4))
I have created accessors for the sublists:
(define (access-name x) (car x))
(define (access-aquprice x)(cadr x))
(define (access-saleprice x)(caddr x))
the sort loop is confusing me,please help! :)
So far all I have is:
(define (sortlist curr)
(if (null? curr)
(curr)
(if (>
(diff (access-aquprice (car toylist)) (access-saleprice (car toylist)))
(diff (access-aquprice (cadr toylist)) (access-saleprice (cadr toylist))))
("hello")
"goodbye")))
Disclaimer: this is the first sort I ever write myself. It may not be bug-free
So you first have to write a basic sort. I suggest you look at this page and pick one. I chose Merge sort since the Wikipedia illustration is nice and it's easy to implement it recursively.
We'll start with sorting a simple list.
So, first the merge:
(define (merge lst1 lst2)
(cond
((null? lst1) lst2)
((null? lst2) lst1)
((> (car lst1) (car lst2))
(cons (car lst2) (merge lst1 (cdr lst2))))
(else
(cons (car lst1) (merge (cdr lst1) lst2)))))
then the merge sort:
(define (merge-sort lst)
(define len (length lst))
(if (<= len 1)
lst
(let ((n (quotient len 2)))
(merge (merge-sort (take lst n)) (merge-sort (drop lst n))))))
(take and drop are defined in SRFI-1 if needed)
Trying:
> (merge-sort '(7 3 0 1 5 8))
'(0 1 3 5 7 8)
> (merge-sort '())
'()
> (merge-sort '(3 14 15 9 26 53 58 97 23))
'(3 9 14 15 23 26 53 58 97)
Looks nice.
Now we'll extend it to use a custom compare function:
(define (merge-sort compare lst)
(define (merge lst1 lst2)
(cond
((null? lst1) lst2)
((null? lst2) lst1)
((compare (car lst1) (car lst2))
(cons (car lst2) (merge lst1 (cdr lst2))))
(else
(cons (car lst1) (merge (cdr lst1) lst2)))))
(define (inner-sort lst)
(define len (length lst))
(if (<= len 1)
lst
(let ((n (quotient len 2)))
(merge (inner-sort (take lst n)) (inner-sort (drop lst n))))))
(inner-sort lst))
then
> (merge-sort > '(7 3 0 1 5 8))
'(0 1 3 5 7 8)
> (merge-sort < '(7 3 0 1 5 8))
'(8 7 5 3 1 0)
Finally, creating a custom compare function for your case:
(merge-sort
(lambda (a b) (> (- (access-aquprice a) (access-saleprice a))
(- (access-aquprice b) (access-saleprice b))))
'((ted 10 4) (barbie 10 5) (car 10 7) (ball 10 6)))
yields
'((car 10 7) (ball 10 6) (barbie 10 5) (ted 10 4))
I know that the question is 3 years old, and you are not allowed to use the built-in sort function, but just in case somebody needs it:
(sort (lambda (x y) (< (- (cadr x) (caddr x))
(- (cadr y) (caddr y))))
'((ted 10 4) (barbie 10 5) (car 10 7) (ball 10 6)))
returns ((car 10 7) (ball 10 6) (barbie 10 5) (ted 10 4))
Cheers!
Andres