(define (find-extrema-helper xs max min length)
(if (null? xs)
(printf "The maximum of your list is ~a and the minimum is ~a." max min)
(let ((head (car xs))
(tail (cdr xs)))
(when (> head max)
(set! max head))
(when (< head min)
(set! min head))
(when (not (null? length))
(set! length (- length 1)))
(when (equal? length 0)
(set! xs null))
(find-extrema-helper tail max min length))))
(define (find-extrema xs)
(let ((max (car xs))
(min (car xs)))
(find-extrema-helper xs max min null)))
(define (find-extrema-sublist-helper xs first length)
(if (> first 0)
(let ((head (car xs))
(tail (cdr xs))
(first (- first 1)))
(find-extrema-sublist tail first length))
(let ((max (car xs))
(min (car xs)))
(find-extrema-helper xs max min length))))
(define (find-extrema-sublist xs first last)
(set! last (- last first))
(find-extrema-sublist-helper xs first last))
Everything works fine except when finding the maximum of the sublist, it's like the length variable is being ignored and it's finding the maximum of the whole list. Thanks for your help.
You almost never need `set!´, and you should recurse over the structure of the list, not its length.
For a nonempty list, the maximum is
the car, if the list has one element (i.e. its tail is the empty list),
the greatest of the car and the maximum of the cdr, if the list is longer.
That is,
(define (max-element x y) (if (> x y) x y))
(define (max-list ls)
(if (null? (cdr ls))
(car ls)
(max-element (car ls) (max-list (cdr ls)))))
The same principle applies to the minimum.
(define (min-element x y) (if (< x y) x y))
(define (min-list ls)
(if (null? (cdr ls))
(car ls)
(min-element (car ls) (min-list (cdr ls)))))
Now you need both, so you should produce a pair (or some other structure).
The trivial method is to use both the previous functions,
(define (extrema ls) (cons (min-list ls) (max-list ls)))
but this is inefficient, since it traverses the list twice.
Let's do better.
This is the same idea applied to both values at the same time:
(define (extrema ls)
(if (null? (cdr ls))
(cons (car ls) (car ls))
(let ((cdr-extrema (extrema (cdr ls)))
(head (car ls)))
(cons (min-element head (car cdr-extrema))
(max-element head (cdr cdr-extrema)))))
Try this:
(define (find-extrema xs)
(if (null? xs) "Empty list."
(printf "The maximum of your list is ~a and the minimum is ~a."
(apply max xs)
(apply min xs))))
If your function expects list as argument, this list can be empty. null? returns #true, if xs is empty list. (null? '()) => #t.
If you need to compare some number with zero, use (= 0 number) instead.
Scheme has in-built functions min and max, but you can't use them on list: (max 1 2 3 4 5) => 5, (max '(1 2 3 4 5)) => error.
But there is apply, which does exactly what you need. (apply max '(1 2 3 4 5)) => (max 1 2 3 4 5) => 5.
By the way, when you name your variables, check whether that name isn't already used (for example min, max, length, first, last). Type that name into REPL and see result: max => #<procedure:max>. Scheme allows you to change value for that variable in given scope, but you will lost previous value. Compare these two functions:
(define (f1 xs first)
(first xs))
(define (f2 xs first-elem)
(first xs))
, that are called like this:
> (f1 '(1 2 3) 1)
> (f2 '(1 2 3) 1)
EDIT: Solution without built-in min and max:
(define (find-extrema-help xs min-num max-num)
(if (null? xs)
(printf "The maximum of your list is ~a and the minimum is ~a." max-num min-num)
(find-extrema-help (cdr xs)
(if (< (car xs) min-num) (car xs) min-num)
(if (> (car xs) max-num) (car xs) max-num))))
(define (find-extrema xs)
(if (null? xs) "Empty list."
(find-extrema-help (cdr xs)
(car xs)
(car xs))))
Find-extrema-sublist:
(define (drop xs number)
(cond ((null? xs) xs)
((= 0 number) xs)
(else (drop (cdr xs) (- number 1)))))
(define (take xs number)
(cond ((null? xs) '())
((= number 0) '())
(else (cons (car xs) (take (cdr xs) (- number 1))))))
(define (find-extrema-sublist xs down-index top-index)
(let ((len (- top-index down-index)))
(find-extrema (take (drop xs down-index)
len))))
Related
I am attempting to write a DrRacket function that that can sort a list in ascending or descending order (by making the comparison operator a parameter). The sorting algorithm should be insertion sort. I called this second parameter cmp.
There are no warnings when I compile, but when I attempt to test the function; for example, (sort-list '(1 0 2 4) >), I receive this error:
sort-list: arity mismatch;
the expected number of arguments does not match the given number
expected: 2
given: 1
arguments...:
Here is my function as of now:
(define (sort-list l cmp)
(define first-element (if (not (null? l)) (car l) 0))
(cond ((null? l) (quote ()))
(else (cons (find-shortest l first-element cmp) (sort-list (remove-member l (find-shortest l first-element cmp)))))))
(define find-shortest
(lambda (tl b cmp)
(cond ((null? tl) b)
((cmp (car tl) b) (set! b (car tl)) (find-shortest (cdr tl) b cmp))
(else (find-shortest (cdr tl) b cmp)))))
(define remove-member
(lambda (tl2 a)
(cond ((null? tl2) (quote ()))
((= a (car tl2)) (cdr tl2))
(else (cons (car tl2) (remove-member (cdr tl2) a))))))
Please, help me with one simple exercise on the Scheme.
Write function, that return count of atoms on the each level in the
list. For example:
(a (b (c (d e (f) k 1 5) e))) –> ((1 1) (2 1) (3 2) (4 5) (5 1))
My Solution:
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(define (count L)
(cond ((null? L) 0)
((pair? (car L))
(count (cdr L)))
(else
(+ 1 (count (cdr L))))))
(define (fun L level)
(cons
(list level (count L))
(ololo L level)))
(define (ololo L level)
(if (null? L)
'()
(if (atom? (car L))
(ololo (cdr L) level)
(fun (car L) (+ level 1)))))
(fun '(a (b (c (d e (f) k 1 5) e))) 1)
It's work fine, but give not correctly answer for this list:
(a (b (c (d e (f) (k) 1 5) e)))
is:
((1 1) (2 1) (3 2) (4 4) (5 1))
But we assume that 'f' and 'k' on the one level, and answer must be:
((1 1) (2 1) (3 2) (4 4) (5 2))
How should I edit the code to make it work right?
UPD (29.10.12):
My final solution:
(define A '(a (b (c (d e (f) k 1 5) e))))
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(define (unite L res)
(if (null? L) (reverse res)
(unite (cdr L) (cons (car L) res))))
(define (count-atoms L answ)
(cond ((null? L) answ)
((pair? (car L))
(count-atoms (cdr L) answ))
(else
(count-atoms (cdr L) (+ answ 1)))))
(define (del-atoms L answ)
(cond ((null? L) answ)
((list? (car L))
(begin
(del-atoms (cdr L) (unite (car L) answ))))
(else
(del-atoms (cdr L) answ))))
(define (count L)
(define (countme L level answ)
(if (null? L) (reverse answ)
(countme (del-atoms L '()) (+ level 1) (cons (cons level (cons (count-atoms L 0) '())) answ))))
(countme L 1 '()))
(count A)
What can you say about this?
Do you know what you get if you run this?
(fun '(a (b (c (d e (f) k 1 5) e)) (a (b (c)))) 1)
You get this:
((1 1) (2 1) (3 2) (4 5) (5 1))
The whole extra nested structure that I added on the right has been ignored. Here is why...
Each recursion of your function does two things:
Count all the atoms at the current "level"
Move down the level till you find an s-expression that is a pair (well, not an atom)
Once it finds a nested pair, it calls itself on that. And so on
What happens in oLoLo when fun returns from the first nested pair? Why, it returns! It does not keep going down the list to find another.
Your function will never find more than the first list at any level. And if it did, what would you to do add the count from the first list at that level to the second? You need to think carefully about how you recur completely through a list containing multiple nested lists and about how you could preserve information at each level. There's more than one way to do it, but you haven't hit on any of them yet.
Note that depending on your implementation, the library used here may need to be imported in some other way. It might be painstakingly difficult to find the way it has to be imported and what are the exact names of the functions you want to use. Some would have it as filter and reduce-left instead. require-extension may or may not be Guile-specific, I don't really know.
(require-extension (srfi 1))
(define (count-atoms source-list)
(define (%atom? x) (not (or (pair? x) (null? x))))
(define (%count-atoms source-list level)
(if (not (null? source-list))
(cons (list level (count %atom? source-list))
(%count-atoms (reduce append '()
(filter-map
(lambda (x) (if (%atom? x) '() x))
source-list)) (1+ level))) '()))
(%count-atoms source-list 1))
And, of course, as I mentioned before, it would be best to do this with hash-tables. Doing it with lists may have some didactic effect. But I have a very strong opposition to didactic effects that make you write essentially bad code.
I've a question, how to return a list without the nth element of a given list? E.g., given list: (1 2 3 2 4 6), and given n = 4, in this case the return list should be (1 2 3 4 6).
A simple recursive solution:
(defun remove-nth (n list)
(declare
(type (integer 0) n)
(type list list))
(if (or (zerop n) (null list))
(cdr list)
(cons (car list) (remove-nth (1- n) (cdr list)))))
This will share the common tail, except in the case where the list has n or more elements, in which case it returns a new list with the same elements as the provided one.
Using remove-if:
(defun foo (n list)
(remove-if (constantly t) list :start (1- n) :count 1))
butlast/nthcdr solution (corrected):
(defun foo (n list)
(append (butlast list (1+ (- (length list) n))) (nthcdr n list)))
Or, maybe more readable:
(defun foo (n list)
(append (subseq list 0 (1- n)) (nthcdr n list)))
Using loop:
(defun foo (n list)
(loop for elt in list
for i from 1
unless (= i n) collect elt))
Here's an interesting approach. It replaces the nth element of a list with a new symbol and then removes that symbol from the list. I haven't considered how (in)efficient it is though!
(defun remove-nth (n list)
(remove (setf (nth n list) (gensym)) list))
(loop :for i :in '(1 2 3 2 4 6) ; the list
:for idx :from 0
:unless (= 3 idx) :collect i) ; except idx=3
;; => (1 2 3 4 6)
loop macro can be very useful and effective in terms of generated code by lisp compiler and macro expander.
Test run and apply macroexpand above code snippet.
A slightly more general function:
(defun remove-by-position (pred lst)
(labels ((walk-list (pred lst idx)
(if (null lst)
lst
(if (funcall pred idx)
(walk-list pred (cdr lst) (1+ idx))
(cons (car lst) (walk-list pred (cdr lst) (1+ idx)))))))
(walk-list pred lst 1)))
Which we use to implement desired remove-nth:
(defun remove-nth (n list)
(remove-by-position (lambda (i) (= i n)) list))
And the invocation:
(remove-nth 4 '(1 2 3 2 4 6))
Edit: Applied remarks from Samuel's comment.
A destructive version, the original list will be modified (except when n < 1),
(defun remove-nth (n lst)
(if (< n 1) (cdr lst)
(let* ((p (nthcdr (1- n) lst))
(right (cddr p)))
(when (consp p)
(setcdr p nil))
(nconc lst right))))
That's elisp but I think those are standard lispy functions.
For all you haskellers out there, there is no need to twist your brains :)
(defun take (n l)
(subseq l 0 (min n (length l))))
(defun drop (n l)
(subseq l n))
(defun remove-nth (n l)
(append (take (- n 1) l)
(drop n l)))
My horrible elisp solution:
(defun without-nth (list n)
(defun accum-if (list accum n)
(if (not list)
accum
(accum-if (cdr list) (if (eq n 0) accum (cons (car list) accum))
(- n 1))))
(reverse (accum-if list '() n)))
(without-nth '(1 2 3) 1)
Should be easily portable to Common Lisp.
A much simpler solution will be as follows.
(defun remove-nth (n lst)
(append (subseq lst 0 (- n 1)) (subseq lst n (length lst)))
)
I'm writing a function that takes a list and returns a list of permutations of the argument.
I know how to do it by using a function that removes an element and then recursively use that function to generate all permutations. I now have a problem where I want to use the following function:
(define (insert-everywhere item lst)
(define (helper item L1 L2)
(if (null? L2) (cons (append L1 (cons item '())) '())
(cons (append L1 (cons item L2))
(helper item (append L1 (cons (car L2) '())) (cdr L2)))))
(helper item '() lst))
This function will insert the item into every possible location of the list, like the following:
(insert-everywhere 1 '(a b))
will get:
'((1 a b) (a 1 b) (a b 1))
How would I use this function to get all permutations of a list?
I now have:
(define (permutations lst)
(if (null? lst)
'()
(insert-helper (car lst) (permutations (cdr lst)))))
(define (insert-helper item lst)
(cond ((null? lst) '())
(else (append (insert-everywhere item (car lst))
(insert-helper item (cdr lst))))))
but doing (permutations '(1 2 3)) just returns the empty list '().
First, construct a family of related examples:
(permutations '()) = ???
(permutations '(z)) = ???
(permutations '(y z)) = ???
(permutations '(x y z)) = ???
Figure out how each answer is related to the one before it. That is, how can you calculate each answer given the previous answer (for the tail of the list) and the new element at the head of the list?
Here is a function, that generates all permutations of numbers with size 'size' , that it consisted of the elements in the list 'items'
(define (generate-permutations items size)
(if (zero? size)
'(())
(for/list ([tail (in-list (generate-permutations items (- size 1)))]
#:when #t
[i (in-list items)]
#:unless (member i tail))
(cons i tail))))
First, I should make it clear that this is required for an academic project. I am trying to find the maximum number of child nodes for any node in a tree, using Common Lisp.
My current code is shown below - I'm not 100% on the logic of it, but I feel it should work, however it isn't giving me the required result.
(defun breadth (list y)
(setf l y)
(mapcar #'(lambda (element)
(when (listp element)
(when (> (breadth element (length element)) l)
(setf l (breadth element (length element)))
))) list)
l)
(defun max-breadth(list)
(breadth list (length list))
)
As an example, running
(max-breadth '(a ( (b (c d)) e) (f g (h i) j)))
should return 4.
Edit:
Trace results and actual return values, forgot these:
CG-USER(13): (max-breadth '(a ( (b (c d)) e) (f g (h i) j)))
0[6]: (BREADTH (A ((B (C D)) E) (F G (H I) J)) 3)
1[6]: (BREADTH ((B (C D)) E) 2)
2[6]: (BREADTH (B (C D)) 2)
3[6]: (BREADTH (C D) 2)
3[6]: returned 2
2[6]: returned 2
1[6]: returned 2
1[6]: (BREADTH (F G (H I) J) 4)
2[6]: (BREADTH (H I) 2)
2[6]: returned 2
1[6]: returned 2
0[6]: returned 2
2
Does anyone have any ideas where I'm going wrong? I suspect it's related to the second conditional, but I'm not sure.
First, standard formatting:
(defun breadth (list y)
(setf l y)
(mapcar #'(lambda (element)
(when (listp element)
(when (> (breadth element (length element)) l)
(setf l (breadth element (length element))))))
list)
l)
(defun max-breadth (list)
(breadth list (length list)))
Your problem is the (setf l y), which should give you a warning about l being undefined. Setf should not be used on unbound variables. Use let to make a lexical scope:
(defun breadth (list y)
(let ((l y))
(mapcar #'(lambda (element)
(when (listp element)
(when (> (breadth element (length element)) l)
(setf l (breadth element (length element))))))
list)
l))
Then, instead of two nested when, use a single one and and:
(when (and (listp element)
(> (breadth element (length element)) 1))
(setf l (breadth element (length element))))
I find dolist more concise here:
(dolist (element list)
(when (and (listp element)
(> (breadth element (length element)) l))
(setf l (breadth element (length element)))))
The parameter y is always the length of the parameter list, so this call can be simplified. You also do not need to alias y:
(defun breadth (list &aux (y (length list)))
(dolist (element list)
(when (and (listp element)
(> (breadth element) y))
(setf y (breadth element))))
y)
You could eliminate the double recursive call through a let, but we can use max here:
(defun breadth (list &aux (y (length list)))
(dolist (element list)
(when (listp element)
(setf y (max y (breadth element)))))
y)
You could also use reduce for this:
(defun breadth (l)
(if (listp l)
(reduce #'max l
:key #'breadth
:initial-value (length l))
0))
L is not a local variable, so the function will return the last value assigned to it (ie, the breadth of the last subtree).
Use LET to declare a local variable:
(LET ((l y))
...
)
Isn't the correct answer 6? Since e and j in your example are also technically child nodes? If that's how you're defining your problem, the following solution should get you there:
(defun max-breadth (lst)
(cond
((atom lst) 0)
((every #'atom lst) (length lst))
(t (+ (max-breadth (car lst)) (max-breadth (cdr lst))))))
version 2:
(defun max-breadth (lst)
(cond
((atom lst) 0)
((every #'atom lst) (length lst))
(t (+
(max-breadth (car lst))
(max-breadth (remove-if-not #'consp (cdr lst)))))))