How would you write a procedure that multiplies each element of the list with a given number (x).If I give a list '(1 2 3) and x=3, the procedure should return (3 6 9)
My try:
(define (mul-list list x)
(if (null? list)
1
(list(* x (car list))(mul-list (cdr list)))))
The above code doesnt seem to work.What changes do I have to make ? Please help
Thanks in advance.
This is the text book example where you should use map, instead of reinventing the wheel:
(define (mul-list lst x)
(map (lambda (n) (* x n)) lst))
But I guess that you want to implement it from scratch. Your code has the following problems:
You should not call list a parameter, that clashes with the built-in procedure of the same name - one that you're currently trying to use!
The base case should return an empty list, given that we're building a list as output
We build lists by consing elements, not by calling list
You forgot to pass the second parameter to the recursive call of mul-list
This should fix all the bugs:
(define (mul-list lst x)
(if (null? lst)
'()
(cons (* x (car lst))
(mul-list (cdr lst) x))))
Either way, it works as expected:
(mul-list '(1 2 3) 3)
=> '(3 6 9)
For and its extensions (for*, for/list, for/first, for/last, for/sum, for/product, for/and, for/or etc: https://docs.racket-lang.org/reference/for.html) are very useful for loops in Racket:
(define (ml2 lst x)
(for/list ((item lst))
(* item x)))
Testing:
(ml2 '(1 2 3) 3)
Output:
'(3 6 9)
I find that in many cases, 'for' implementation provides short, simple and easily understandable code.
Related
Ultimately, i shall be trying to reimplement sorting algorithms in scheme for linked lists. I have written a subprocedure that will help me along the way. The goal is to simply swap 2 elements, given as arguments "pair1 and pair2" and then return the list.
(define (cons-til lst until)
(cond
((or (null? lst) (eq? (car lst) until)) '())
(else (cons (car lst) (cons-til (cdr lst) until)))))
(define (swap lst pair1 pair2)
(cons (cons (append (cons-til lst (car pair1))
(car pair2)) (car pair1)) (cdr pair2)))
(define my-list '(1 2 3 4 5 6 7))
(swap my-list (cdr (cdr my-list)) (cdr (cdr (cdr my-list))))
When the code is executed, it returns:
(((1 2 . 4) . 3) 5 6 7)
How can i fix this in order to have a plain scheme list. The element seems to have swapped correctly.
Two suggestions:
Do you really want to write n cdr calls to index the nth element? I recommend strongly using integer indexes (if you need them, that is).
Referring to elements by index in a linked list (i. e. “random access”) is not very efficient most of the time, especially when done in loops. I strongly recommend using either vectors or a better suited algorithm that doesn't need random access, e. g. merge sort.
(define (swap2 lst pair1 pair2)
(append (append (append (cons-til lst (car pair1))
(list (car pair2)))
(list (car pair1))) (cdr pair2)))
This code seems to work. I'm not sure this is completely efficient or a smart solution to the problem. Looking forward to other suggestions. The value given back is '(1 2 4 3 5 6 7)
For the built-in function foldr, I know the function blueprint is the following:
(foldr combine base alist)
combine is supposed to take in two parameters:
an item that foldr consumes
the result of applying foldr to the rest of alist
I cannot seem to understand how to put point #2 in parameter form ever. How did you do it?
combine is not a built-in function. I would have to code it myself based on the requirements.
Think of second parameter as the accumulated value so far. For example, if we are adding the elements, then acc is the sum of all the previous eles and we need to add the current element:
(foldr (lambda (ele acc) (+ ele acc))
0 ; we're adding numbers, so the base is 0
'(1 2 3 4 5))
=> 15
Another example - if we're copying the list, then acc contains the previous eles in the list (starting from the last one and going back from there) and we have to cons the current element at the head :
(foldr (lambda (ele acc) (cons ele acc))
'() ; we're creating a list, so the base is an empty list
'(1 2 3 4 5))
=> '(1 2 3 4 5)
The exact nature of acc depends on the problem to be solved, but you should be able get the idea from the previous examples.
Think of it as the result computed so far and that foldr iterates from end to beginning while a foldl iterates from beginning to end. It's easier to see if you look at a simple implementation of it:
(define (foldr1 f init lst)
(let r ((lst lst))
(if (null? lst)
init
(cons (f (car lst)) (r (cdr lst))))))
(foldr1 combine base '(1 2 3)) ; ==
(combine 1 (combine 2 (combine 3 base)))
(define (foldl1 f init lst)
(let r ((lst lst) (acc init))
(if (null? lst)
acc
(r (cdr lst) (f (car lst))))))
(foldl1 combine base '(1 2 3)) ; ==
(combine 3 (combine 2 (combine 1 base)))
Also note that the order or the arguments change in some implementations. Racket and SRFI-1 always have the accumulator as the last argument, but in R6RS the argument order changes for fold-left (but not fold-right):
#!r6rs
(import (rnrs))
;; swap argument order
(fold-left (lambda (acc e) (cons e acc)) '() '(1 2 3))
; ==> (3 2 1)
Pretty straightforward question. My initial approach was to define another procedure to find the last element of lst within first-last. After finding the last element I appended it with the first element of lst (car lst).
This is how append works.
(append list1 list2)
e.g., (append '(1 2 3) '(2 1 5)) -> (1 2 3 2 1 5)
I'm wondering if the problem is just with my syntax but I am not sure.
(define (first-last lst)
(define (last lst)
(cond ((null? (cdr lst))(car lst))
(else (last (cdr lst)))))
(append(car lst)(last lst)))
The error occurs in the
(append(car lst)(last lst)))
"mcar: contract violation
expected: mpair?
given: 1"
This is my first question on stack, so I'm sorry if the question is not presented in the correct way.
append is only for joining two or more lists. Here, though, you're not joining existing lists, but building a list from two elements. For that, use list:
(list (car lst) (last lst))
If you can use match, a neat solution is possible:
(define first-last
(lambda (x)
(match x
((first rest ... last)
(list first last))
((only) (list only only))
(_ #f))))
Of course, you could return something other than #f in the catch-all clause.
So I have to remove the last element of a list in scheme.
For example, let's say I have a list (1 2 3 4). I need to return:
(1 2 3)
My idea:
reverse(list)
car(list)
reverse(list)
Is there a reverse function in scheme(racket)?
You wrote: "reverse, car, reverse". I believe you meant to write "reverse, cdr, reverse". There's nothing wrong with this solution; it's linear in the size of the list, just like any solution to this that uses the standard lists.
As code:
;; all-but-last: return the list, not including the last element
;; list? -> list?
(define (all-but-last l) (reverse (cdr (reverse l))))
If the multiple traversal of the list or the needless construction of another list copy bothers you, you can certainly avoid it, by writing the thing directly.
Given your almost-solution, I'm going to assume that this isn't homework.
Here's what it would look like, in racket:
#lang racket
(require rackunit)
;; all-but-last : return the list, except for the last element
;; non-empty-list? -> list?
(define (all-but-last l)
(cond [(empty? l) (error 'all-but-last "empty list")]
[(empty? (rest l)) empty]
[else (cons (first l) (all-but-last (rest l)))]))
(check-equal? (all-but-last '(3 4 5))
'(3 4))
There is a reverse, but using it would not be very efficient. I suggest the following recursive function.
(define (remove-last lst)
(if (null? (cdr lst))
'()
(cons (car lst) (remove-last (cdr lst)))))
(remove-last '(1 2 3 4)) ; returns '(1 2 3)
The if checks whether it is at the last element of the list.
SRFI 1 (activate in Racket using (require srfi/1)) has a drop-right function:
(drop-right '(1 2 3 4) 1) ; => (1 2 3)
I would do a recursive function that goes down the list and attaches the element (using cons) if the element after it is not the last, and appends nothing if it isn't.
I haven't done scheme for years though so that's as far as I can go.
Someone can run with how to implement it (unless it's homework then they probably shouldn't!)
I've done something simpler than: reverse(list), car(list), reverse(list) to get the last element, check out:
(define (last-one liste)
(if(null? (cdr liste))
null
(cons (car liste) (last-one (cdr liste)))
)
)
Those who are looking for another way can check this out:
(define (removing-last xx)
(remove (list-ref xx (- (length xx) 1)) xx))
I would write a simple recursion, altering the typical "empty? mylist" base case to "empty? (rest mylist)," so that I can return empty when the input list is only 1 element.
(define (removelast mylist)
(cond
[(empty? (rest mylist)) empty]
[(cons? mylist) (cons (first mylist) (removelast (rest mylist)))]))
(removelast (list 1 2 3 4 5))
By the way, this code is in Racket/PLT Scheme, a subset of Scheme.
Hey guys, I'm using MIT Scheme and trying to write a procedure to find the average of all the numbers in a bunch of nested lists, for example:
(average-lists (list 1 2 (list 3 (list 4 5)) 6)))
Should return 3.5. I've played with the following code for days, and right now I've got it returning the sum, but not the average. Also, it is important that the values of the inner-most lists are calculated first, so no extracting all values and simply averaging them.
Here's what I have so far:
(define (average-lists data)
(if (null? data)
0.0
(if (list? (car data))
(+ (average-lists (car data)) (average-lists (cdr data)))
(+ (car data) (average-lists (cdr data))))))
I've tried this approach, as well as trying to use map to map a lambda function to it recursively, and a few others, but I just can't find one. I think I'm making thing harder than it should be.
I wrote the following in an effort to pursue some other paths as well, which you may find useful:
(define (list-num? x) ;Checks to see if list only contains numbers
(= (length (filter number? x)) (length x)))
(define (list-avg x) ;Returns the average of a list of numbers
(/ (accumulate + 0 x) (length x)))
Your help is really appreciated! This problem has been a nightmare for me. :)
Unless the parameters require otherwise, you'll want to define a helper procedure that can calculate both the sum and the count of how many items are in each list. Once you can average a single list, it's easy to adapt it to nested lists by checking to see if the car is a list.
This method will get you the average in one pass over the list, rather than the two or more passes that solutions that flatten the list or do the count and the sums in two separate passes. You would have to get the sum and counts separately from the sublists to get the overall average, though (re. zinglon's comment below).
Edit:
One way to get both the sum and the count back is to pass it back in a pair:
(define sum-and-count ; returns (sum . count)
(lambda (ls)
(if (null? ls)
(cons 0 0)
(let ((r (sum-and-count (cdr ls))))
(cons (+ (car ls) (car r))
(add1 (cdr r)))))))
That procedure gets the sum and number of elements of a list. Do what you did to your own average-lists to it to get it to examine deeply-nested lists. Then you can get the average by doing (/ (car result) (cdr result)).
Or, you can write separate deep-sum and deep-count procedures, and then do (/ (deep-sum ls) (deep-count ls)), but that requires two passes over the list.
(define (flatten mylist)
(cond ((null? mylist) '())
((list? (car mylist)) (append (flatten (car mylist)) (flatten (cdr mylist))))
(else (cons (car mylist) (flatten (cdr mylist))))))
(define (myavg mylist)
(let ((flatlist (flatten mylist)))
(/ (apply + flatlist) (length flatlist))))
The first function flattens the list. That is, it converts '(1 2 (3 (4 5)) 6) to '(1 2 3 4 5 6)
Then its just a matter of applying + to the flat list and doing the average.
Reference for the first function:
http://www.dreamincode.net/code/snippet3229.htm