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
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 trying to learn clisp and I have started learning how to manipulate lists recursively. I am unsure wether it is my logic or if I am just too unfamiliar with the constructs of lisp, for some I am able to do it i.e. for procedure (separate '(a 1 b 2 c 3 d 4)) => ((1 2 3 4) (a b c d)) by doing
(defun separate (lst)
(if (endp lst)
'(nil nil)
(let ((x (separate (cdr lst))))
(if (numberp (car lst))
(list (cons (car lst)
(car x)))
(list (car x)
(cons (car lst) (cadr x)))))))
but when I do the same approach for another procedure
(greater-than-n '(9 1 8 2 7 3 6 4) 5)
I would expect to get a list : ((9 8 7 6) (1 2 3 4))
but instead I get: ((9 8 7 6))
My program thus far is:
(defun greater-than-n (lst n)
(if (endp lst)
'(() ())
(let ((x (greater-than-n (cdr lst) n)))
(if (> (car lst) n)
(list (cons (car lst)
(car x)))
(list (car x)
(cons (car lst)
(car x)))))))
I appreciate any help or comments.
Your bug is in the
(list (cons (car lst)
(car x)))
form: you are returning a list of 1 element.
PS. Your functions seem like a textbook case for using multiple values instead of a list of values.
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)
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)
I am writing a recursive code to Bubble Sort (smallest to largest by swapping)
I have a code to do the bubble sort just once
(define (bubble-up L)
(if (null? (cdr L))
L
(if (< (car L) (cadr L))
(cons (car L) (bubble-up (cdr L)))
(cons (cadr L) (bubble-up (cons (car L) (cddr L))))
)
)
if i put a list into this code, it returns the list with the largest number at the end
EX.. (bubble-up ' (8 9 4 2 6 7)) -> ' (8 4 2 6 7 9)
Now i am trying to write a code to do the (bubble-up L) N times (the number of integers in list)
I have this code:
(define (bubble-sort-aux N L)
(cond ((= N 1) (bubble-up L))
(else (bubble-sort-aux (- N 1) L)
(bubble-up L))))
(bubble-sort-aux 6 (list 8 9 4 2 6 7)) -> ' (8 4 2 6 7 9)
But the recursion doesn't seem to happen because it only sorts once!
Any suggestions would be welcome, i'm just stumped!
Try this:
(define (bubble-sort-aux N L)
(cond ((= N 1) (bubble-up L))
(else (bubble-sort-aux (- N 1) (bubble-up L)))))
If you keep "bubbling-up" the list N times it'll be sorted at the end. The problem with your code is that you weren't using the result of bubble-up for anything - but if we pass the value returned by bubble-up to the next call of the function, it'll eventually be sorted. Now the procedure works as expected:
(bubble-sort-aux 6 (list 8 9 4 2 6 7))
=> '(2 4 6 7 8 9)
My implementation:
(define (bubble-swap ls)
(if (null? (cdr ls))
ls
(if (> (car ls) (cadr ls))
(cons (cadr ls) (bubble-swap (cons (car ls) (cddr ls))))
(cons (car ls) (bubble-swap (cdr ls))))))
(define (len ls)
(if (null? ls)
0
(+ 1 (len (cdr ls)))))
(define (bubblesort_ ls n)
(if (= n 1)
ls
(bubblesort_ (bubble-swap ls) (- n 1))))
(define (bubblesort ls) (bubblesort_ ls (len ls)))
I implemented a custom len function but you can use standard length function, if available.