DrRacket - Display all the values in a list that are above average - racket

I'm creating a function that consumes a list of numbers and produces the elements in the list that are above average.
Below is my code:
(define (listlength list)
(cond
((empty? list) 0)
(else (+ 1 (listlength (rest list))))))
(define (listsum list)
(cond
[(empty? list) 0]
[else (+ (first list)
(listsum (rest list)))]))
(define (average log)
(/ (listsum log) (+ (listlength log) 1)))
(define (average-filter log)
(cons
(cond
[(> (first log) (average log)) (first log)]
[else (average-filter (rest log))])))
So obviously there is something wrong with my code...Can someone help me?
The error message for (average-filter (cons 40 (cons 30 empty) is:
cons: expects 2 arguments, but found only 1

A couple of comments: in the average procedure, there's no need to add 1 to the denominator, but you should handle the case when it's zero. Also notice that you can improve your solution by calculating the average only once, it'll be the same for the input list, so you don't need to recalculate it at every iteration. And please don't call your parameters list or log, they will clash with existing procedures.
Now for the real issue with average-filter: it's the same error of your previous question, you must not put the cons part at the beginning, that's not how it works. You should call cons with the current element and the result of the recursive call, to build a list with the results. And you must have a base case, think about it: what would happen when you run out of elements to traverse? that's the point where you need to return an empty list:
(define (average-filter lst)
(cond
[(empty? lst) empty]
[(> (first lst) (average lst))
(cons (first lst) (average-filter (rest lst)))]
[else (average-filter (rest lst))]))
Please, spend some time studying the proper way to build an output list as a result of traversing an input list, notice that you need to:
Handle the case when the input list is empty.
cons the current element with the result of the recursive call, when it makes sense to do it.

Related

Why does this LISP code emit periods or complain that lists must not end in 4?

I just started learning LISP today just for the heck of it, so I am completely new to it. I do have experience in other languages though. I tried to write a function that returns a list exactly as is, except without the last element.
While I intend to rewrite this function anyway since I'm sure there's a simpler way of doing it, my version produced some very unusual output. For the record, I'm using the CLISP environment.
(defun my-butlast (L)
(if (null (rest L))
nil
(if (eq nil (my-butlast (rest L)))
(first L)
(cons (first L) (my-butlast (rest L)))
)
)
)
(my-butlast '(1 2 3 4 5))
This produced the output (1 2 3 . 4)
And so my question is, where did the point come from?
Also, if I try to run (length (my-butlast '(1 2 3 4))) I get a mystifying error: A proper list must not end with 4. What does that mean?
. is used in the representation of a cons whose cdr is not NIL. E.g.
(cons 1 2)
is displayed as
(1 . 2)
Consider what happens in your function if you do
(my-butlast '(1 2))
The test (eq nil (my-butlast (rest L)) will be true, so it returns (first L). Notice that this is just the number 1, not a list containing 1. You need to change to:
(if (eq nil (my-butlast (rest L)))
(list (first L))
(cons (first L) (my-butlast (rest L)))
)
Incidentally, it's more idiomatic to write (null (my-butlast (rest L))).
Try doing I believe for your base case (it's been a while since I wrote lisp):
(list (first L))
(first L) will not return a list and cons of one element to another will create the structure you are looking at. Essentially your linked list is ending in [3|4] instead of [3|->] [4|0] with my lame ascii box diagrams.

Help using Lisp debugger

I'm trying understand how to interpret the output of, and use, the Lisp debugger.
I've got a pretty simple Backtrace for the evaluation of my function, but I cann't seem to work out how to use it to find out in which Lisp 'form' in my function the exception occurred.
I'd appreciate any clues as to what I should be doing, to find where in my code the error originated.
Also - why does the second frame display as "no debug information available for frame"?
I've attached a screen shot with the debugger, and repl (I've also included my function below - I know it's very wrong - but I'm just interested in learning to use the debugger properly). In addition, I hit 'v' on the first frame to go to the source, but this resulted in the error below the repl. (EDIT - the missing source code issue is fixed by downloading & copying it to the correct path)
(horrible function - no comments please!)
(defun myquicksort2 (lst)
(if (eql 1 (length lst))
lst
(let ((mid (middle lst)))
(do ((i 0 (+ i 1)))
((>= i mid) (append (myquicksort2 (subseq lst 0 mid))
(myquicksort2 (subseq lst mid (length lst)))))
(if (> (ltval i lst) (nth 100 lst))
(let ((tmp (ltval i lst)))
(setf (nth i lst) (gtval i lst))
(setf (nth (- (- (length lst) i) 1) lst) tmp)))))))
(defun ltval (i lst)
(nth i lst))
(defun gtval (i lst)
(nth (- (- (length lst) i) 1) lst))
(defun middle (lst)
(round (/ (length lst) 2)))
The error is with > and you have only one > in your source, so that's where the problem is.
edit Built-in CL functions are highly prone to optimization in SBCL, so although the function call in your code is to CL:<, the code that's actually called (and which shows up in the debugger) is from an optimized, specific, SBCL-internal routine. This is less of an issue for user-defined functions, where you will be much more likely to get a useful frame.

Get Last Element of each list

Let us say I have a list ((3 4 5) (d e f) (h i j) (5 5 5 5))
How can I get the last element of each list in such a way that the output would look like this (5 f j 5)?
Assuming this is about Common Lisp, there is a function last which returns a list containing the last item of a list. If you use this function with mapcan, which applies a given function to each element of a list and returns the concatenated results, you'll get what you want.
Note though that accessing the last element of a list is an O(N) operation, so if this isn't just homework after all, you might want to consider if you can't solve the real problem more efficiently than taking the last item of each list (maybe use another datastructure instead).
This, like most early LISPy homework problems is an exercise in thinking recursively and/or thinking in terms of induction. The way to start is to ask yourself simple questions that you can answer easily.
For example, if you had been asked to write something that gave you the first element in each list, I would thing about it this way:
Given a list of lists:
What is first-element of every list in the list '()? (easy - null)
What is first-element of every list in the list '(a)? (easy - a, or maybe an error)
What is first-element of every list in the list '((a))? (easy - (a))
What is first-element of any list in the form '(anything), where anything is a list? (easy - (first anything))
What is the first element of every list in the form '(anything morestuff)? (easy - (cons (first anything) (first-element morestuff)) )
What is first of an atom? either the atom or an error (depends on your point of view)
What is first of null? nil.
What is first of a list? (car list)
From here we can start writing code:
;; here's first, meeting questions 6-8
(define first (lambda (l)
(cond
((null? l) nil) ; Q7
((atom? l) l) ; Q6
(t (car l))))) ; Q8
;; with first we can write first-element, meeting questions 1-5
(define first-element (lambda (l)
(cond
((null? l) nil) ; Q1
((atom? l) (first l)) ; Q2
(t (cons (first (car l) (first-element (cdr l)))))))) ; Q4-5
Now this isn't your homework (intentionally). You should play with this and understand how it works. Your next goal should be to find out how this differs from your assignment and how to get there.
With respect to MAPCAR? Don't worry about it. You need to learn how to solve recursive problems first. Then you can worry about MAPCAR. What is the point of this assignment? To help you learn to think in this mode. Dang near everything in LISP/Scheme is solved by thinking this way.
The reason I went with all the questions to break it down into the parts that I'm worried about. If I'm given the task "how do I do foo on every item in a list?" I should answer the questions: How do I do handle null? How do handle an atom? How do I do handle on the first element on the list? How do I handle everything else? Once I've answered that, then I figure out how to actually do foo. How do I do foo on null? How do I do foo on an atom? How do I do foo on a list?
(defun get-last-lists (s)
(setq rt 'nil)
(loop for i from 0 to (- (length s) 1)
do (setq rt (append rt (last (nth i s)))))
(print rt))
as a beginner of lisp, i post my solution.
Write a procedure that returns the last element of a list, then learn a little about the built-in MAP (a.k.a. MAPCAR) procedure and see if any lightbulbs go off.
probably it is already solved, but I figured this out
; SELECT-FROM-INNER-LIST :: [list] -> [list]
(DEFUN SFIL (lst)
(COND ((NULL lst) NIL)
((LISTP (FIRST lst)) (APPEND (LAST (FIRST lst)) (SFIL (REST lst))))
))
Now, this works for legit list...so if you call function SFIL with correct list.... if not, it will return NIL
hopefully this will be helpful, for anyone who finds it

Homework: Lisp items that appear more than once in a list

Given a list, I'm trying to return a new one that has only the items that appear more than once in the first list I receive as a parameter.
I have done the following:
(defun myf (lista)
(if (endp lista)
nil
(if (member (first lista) (rest lista))
(append (list (first lista)) (myf (rest lista)))
(myf (rest lista)))))
If I run the following: (myf '(A A B A B C)), it returns (A A B).
How can I make it return items only once (i.e., not have double "A")?
Once you've found that a letter is in the list more than once, you don't need to check it again, so you don't need it in the rest of the list. So you could modify the remaining list...
Note: this answer intentionally somewhat vague, since it's for homework and all. :)
The problem seems to be that you are checking to see if the first element of the list is in the tail of the list and appending it to the result list. The problem comes up when you come to the second instance of A, which when checked says yes it is in the tail because there is a 3rd instance of A in the list. If the input list had 4 A's then it would return 3 of them.
So to solve this need to check if A is already a member of the result list. That is, if first lista is not a member of list then append first lista to list.
Vincent, Gishu and Jerry hinted that you need to check if the item is already in the result list before appending to it, while Derek hinted that you could modify the original list when you see that an item is repeated.
Read the documentation of the functions adjoin and remove here:
http://www.lispworks.com/documentation/HyperSpec/Body/f_adjoin.htm
http://www.lispworks.com/documentation/HyperSpec/Body/f_rm_rm.htm
The HyperSpec is a very useful reference, add it your bookmarks.
Those two functions do not modify their arguments, but instead return the result as a new list. There are other functions that DO modify their arguments and thus might be more efficient, but at this point perhaps you shouldn't worry about them.
OK, I hope that by the time I have written this you have figured it out. If not, keep trying, that's the only way you'll really learn.
Now I'd like to talk to you about another approach, and that is about carrying the result through the recursive calls.
Our function repeated will do nothing but call a helper function repeatedr which will do the actual work, passing to it an initial empty result '():
(defun repeated (lst)
(repeatedr lst '()))
Now let's define the helper function, it receives two parameters: the list to search for duplicates, and the result list where we will accumulate the duplicate items.
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
When the condition (member (first lst) (rest lst)) holds true we will adjoin the first item to the result, and the result of that adjoining will be passed to the recursive call as the second parameter; otherwise we just pass the result as is to the recursive call.
When the list is finally empty (if (null lst) we will return the result.
> (repeated '(a a b a b c))
(B A)
Notice that the result is (B A) and maybe you were expecting it to be (A B). Try to follow the execution of the recursive calls and the values of the parameters at each call with pen and paper, that will be a good exercise, and you'll have to play with adjoin to understand its behaviour. If you want to get the result reversed you can modify the function like this:
(defun repeatedr (lst result)
(if (null lst)
(reverse result)
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
This reverses the result when the recursion finishes.
Now, what about the suggestion of removing the duplicate elements from the list before going forward? We could have written our function like this:
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (remove (first lst) lst) (cons (first lst) result))
(repeatedr (rest lst) result))))
Try to play with remove at the REPL:
> (remove 'a '(a b c d a e f b a d))
(B C D E F B D)
Notice that we are no longer adjoining to the result, instead we just create a new "cons cell" with (cons (first lst) result). cons and adjoin do the same thing, except that adjoin will add the value only if it is not already present in the list.
Hope this gives you something to play with.
The problem seems to be that you're not checking if the element exists in the output list before appending to it.
Right now, for each element in the list, you're adding that element to the result if its not contained in the remainder of the list.
To get the result you apparently want, you'd add each element in the list to the result if it's not yet contained in the result.
If order is not a concern then you can also do:
(defun my-fun-no-order (lst)
(loop for (item . rest) on lst
when (= (count item rest) 0)
collect item))
Here we iterate over a list spitting it into the current item being iterated over and the rest of the items yet to be examined. The when clause determines the situation under which we collect the item.

How can I tell if a list has a third item?

I have a function that takes a list that either has two or three elements.
;; expecting either ((a b c) d) or ((a b c) d e)
(define (has-third-item ls)
(if (null? (caddr ls))
false
true)
)
But this code fails with
mcar: expects argument of type <mutable-pair>; given ()
on the (null? (caddr ls)) expression.
I also tried
(eq? '() (caddr ls))
but it didn't work either. How do I tell if there's a third item or not?
You don't want caddr, you want (if (null? (cddr ls)) ... Or just use length to find the length of the list, and compare it to the value you're interested in.
The '() that terminates a list will always be in the cdr position of a pair, so looking for it in the car position (which cad+r will do) isn't going to be productive.
The problem is that if you have a list with two or fewer items, you can't take the caddr of it. Try this:
(define (has-third-item lst)
(<= 3 (length lst)))
There could be some cases where taking the length of the list can be inefficient (such as the list containing millions of items); in this case, we can test to see if the list has length zero, one, or two by hand:
(define (has-third-item lst)
(not (or (null? lst)
(null? (cdr lst))
(null? (cddr lst)))))
edit: Regarding the two other answers, while taking the cddr may work in this case as the input domain consists of list with either two or three elements, has-third-item would still fail for lists with zero or one. In the interest of generality, I suggest going with a solution that works for any domain.
Provided you know your list has either two or three elements (as you say it has), you can do
(define (has-third-item? l)
(not (null? (cddr l))))
You're checking whether the second cons cell (cddr l) has a cdr or not. You don't have to check whether l itself is null or l has only one element, unless you want a more generic function.
try...
(and l (cdr l)(cddr l))
Why not use (third ls)
Will return the third element or NIL if none is present.