(defun suma (L)
(setq var 0)
(do
((i 0 (+ i 1)))
((= i (length L)))
(+ var (nth i L)))
var)
Why does it always returns 0?
Shouldn't it return sum of list L?
+ does not modify its arguments, so, since you never modify var, its initial value of 0 is returned.
You need to replace (+ var (nth i L)) with (incf var (nth i L)), of, equivalently, (setq var (+ var (nth i L))).
See incf.
Note that you should bind var with let instead of making it global with setq.
Most importantly, note that your algorithm is quadratic in the length of the list argument (because nth scans your list every time from the start).
Here are some better implementations:
(defun sum-1 (l)
(reduce #'+ l))
(defun sum-2 (l)
(loop for x in l sum x))
(defun sum-3 (l)
(let ((sum 0))
(dolist (x l sum)
(incf sum x))))
Here is a bad implementation:
(defun sum-4 (l)
(apply #'+ l))
The problem with sum-4 is that it will fail if the length of the supplied list is larger than call-arguments-limit.
I thought this would be a comment for the full learning experience, but I was not able to put code in the comment.
There is a way to do sums without modifying any argument, and that is by doing it recursively:
(defun recsum (list)
(if list
(+ (first list) (recsum (rest list)))
0))
This version can be tail call optimized by the compiler, and as fast as a loop:
(defun recsum2 (list &optional (accumulator 0))
(if list
(recsum2 (rest list) (+ accumulator (first list)))
accumulator))
What you are trying to do could be done with do like this:
(defun suma (l)
(do
((var 0)
(i 0 (+ i 1)))
((= i (length l)) var)
(incf var (nth i l))))
But we don't usually do anything in dos body, so it's like this then:
(defun suma (l)
(do
((i 0 (+ i 1))
(var 0 (+ var (nth i l))))
((= i (length l)) var)))
But nth and length are slow, so better do it this way:
(defun suma (l)
(do*
((var (first l) (+ var (first list)))
(list (rest l) (rest list)))
((null list) var)))
This one is without the * in do, and returns 0 on empty list:
(defun suma (l)
(do
((acc 0 (+ acc (first list)))
(list l (rest list)))
((null list) acc)))
But my favorite is the reduce version from #sds which also can return 0 on empty list with :initial-value 0
EDIT: recsum2 did not return anything, so it needed a fix.
Related
I'm trying to get a list with the average of the following n elements. I'm reading a csv file that has 7 columns im just using the 6th one that has number values in order to get the average.
This is the code
;Function that returns a list containing the values of the desired column
(define (get-column col)
(let loop
([file (cdr(all-rows csv-path read-csv))]
[result empty])
(if (empty? file)
result
(loop (cdr file)
(cond
[(equal? col 1) (append result (list (caar file)))]
[(equal? col 2) (append result (list (string->number(cadar file))))]
[(equal? col 3) (append result (list (string->number(caddar file))))]
[(equal? col 4) (append result (list (string->number(car (cdddar file)))))]
[(equal? col 5) (append result (list (string->number(cadr (cdddar file)))))]
[(equal? col 6) (append result (list (string->number(caddr (cdddar file)))))]
[(equal? col 7) (append result (list (string->number(car (cdddr (cdddar file))))))]
)))))
(define (suma-SMA col n)
(let loop
([n n]
[res 0]
[col col])
(if (zero? n)
res
(loop (sub1 n) (+ res (car col)) (cdr col)))))
(define (get-SMA days)
(let loop
([col (get-column 6)]
[result empty])
(if (empty? col)
result
(loop (cdr col)(append result (list (suma-SMA col days)))))))
Here's a function that does what you asked for in the comments, e.g. given (1 2 3 4) it produces ((1+2)/2 (2+3)/2 (3+4)/2).
(define (sum list)
(cond
((null? list)
'()) ;; error?
((null? (cdr list))
'())
(else
(cons (/ (+ (car list) (cadr list)) 2) (sum (cdr list))))))
I'm still a bit confused because even the combination of get-SMA and suma-SMA does nothing like this. It's completely unclear what the days variable is doing, as you can see I didn't need it in my code above.
So I may have misunderstood what you are trying to do, but the function above does what you actually asked for so hopefully it will be helpful.
Here is the answer that I found useful for my problem.
(define (sum list n)
(cond
((null? list)
'()) ;; error?
((null? (cdr list))
'())
(else
(cons (suma-SMA list n) (sum (cdr list) n)))))
I'm begginer at LISP, and I have a question need your help.
Write a function COUNT-NUMBERS that counts the number of numbers in a list,and return " NO NUMBER" if there is no number in the list
For example, for a list: (A 2.3 B C 4 5), it returns 3.
I've tried with the following code, but it doesn't work . Could you help me to figure out? Moreover, I don't know how to return "NO NUMBER" if there is no number in the list.
(defun count-numbers (x)
(cond ((null x) 0)
((numberp x) 1)
(t (+(count-numbers (car x))(count-numbers (cdr x))))))
Thanks in advance,
You could to define a inner helper function to do the counting, and check the result to decide what to return in the main function:
(defun number-counter (lst)
(labels ((do-count (l)
(cond ((null l) 0)
((numberp (car l)) (+ 1 (do-count (cdr l))))
(t (do-count (cdr l))))))
(let ((r (do-count lst)))
(if (= r 0) 'NO-NUMBER r))))
This would be a tail-recursive version. Somehow you have to check what to return.
(defun count-numbers (list &optional (n 'no-number))
(cond ((null list) n)
((numberp (first list))
(count-numbers (rest list)
(if (eq n 'no-number)
1
(1+ n))))
(t (count-numbers (rest list) n))))
With a LOOP you can write that this way:
(defun count-numbers (list)
(loop for element in list
count (numberp element) into n
finally (return (if (zerop n) 'no-number n))))
Given a list, and a number, n, I am trying to split a list into two separate lists: one into a list of length n, and the second list being the rest of the original list.
Here is what I have:
(define (part lst i)
(if (> i 0)
(list (append (list (first lst)) (list (part (rest lst) (- i 1)))))
(append lst)))
Where lst is the inputted list, and i is the number. When I input the list '(1 2 3 4) with the number 2, I return an output of: '((1 ((2 (3 4))))) instead of what I want which is '((1 2) (3 4)).
This is for a homework assignment, so it would be much appreciated if someone could just point me in the right direction as to where my problem lies, and because it is a hw assignment, I only am allowed to use the simple racket functions.
EDIT:
When I change the code to:
(define (part lst i)
(if (> i 0)
(append (list (first lst)) (list (part (rest lst) (- i 1))))
(append lst)))
I get an output of '(1 (2 (3 4))).
Using existing libraries
There's an easy way to solve this problem in Racket, just use the built-in split-at procedure (also available in the SRFI-1 library). This has the advantage of making a single pass across the input list:
(define (part lst i)
(let-values (((head tail) (split-at lst i)))
(list head tail)))
Another option would be to use Racket's built-in procedures take and drop (also available in SRFI-1) - but this will make two passes across the input list:
(define (part lst i)
(list (take lst i)
(drop lst i)))
Implementation from scratch
To build our own solution, we could write a procedure that makes a single pass, like this:
(define (part lst i)
(if (negative? i)
(error "index can't be negative")
(let loop ((lst lst) (acc '()) (i i))
(cond ((and (empty? lst) (positive? i))
(error "index is too large for list"))
((zero? i)
(list (reverse acc) lst))
(else
(loop (rest lst) (cons (first lst) acc) (sub1 i)))))))
Also, we could implement our own versions of take and drop - again, this will traverse the input list twice:
(define (my-take lst i)
(if (> i 0)
(cons (first lst)
(my-take (rest lst) (- i 1)))
'()))
(define (my-drop lst i)
(if (> i 0)
(my-drop (rest lst) (- i 1))
lst))
(define (part lst i)
(list (my-take lst i)
(my-drop lst i)))
beginner in LISP here. I'm preparing myself for my upcoming exam in LISP and I've come across a problem I can't solve, so I was hoping someone more experienced might help me out.
Anyways, here is my problem :
You are given a list that may contain lists as elements. Your task is to delete an atomic element at a given position.
The list and the position are given as input parameters.
Example : Position=5 , List=(1 (2 3) ((4)) (5 (6))) , should return (1 (2 3) ((4)) ((6))).
Here is what i got so far...(PS the code below works thanks to the assistance of imMaw , you can check edit to see my previous mistake ).
(defun number_of_atoms(List)
(atoms List 0)
)
(defun atoms(List Number)
(cond
((null List) Number)
((atom (car List)) (atoms (cdr List) (+ 1 Number)))
((+ (atoms (car List) Number) (atoms (cdr List) 0)))
)
)
(defun deleteElement(Pos List)
(deleteElementAcc Pos 1 List)
)
(defun deleteElementAcc(Pos CurrPos List)
(cond
((null List) nil)
((and (atom (car List)) (not(eql CurrPos Pos))) (cons (car List) (deleteElementAcc Pos (+ CurrPos 1) (cdr List))))
((and (atom (car List)) (eql CurrPos Pos)) (deleteElementAcc Pos (+ CurrPos 1) (cdr List)))
((cons (deleteElementAcc Pos CurrPos (car List))
(deleteElementAcc Pos (+ CurrPos (number_of_atoms(car List))) (cdr List))))
)
)
Why are you spelling Pos and CurrPos with z's in half the places?
And the problem in your code lies in the last branch of the cond. When you recurse on the cdr of List, CurrPos needs to be advanced by the number of elements in (car List). And a simple (length List) won't work, because it needs to recursively count elements in sublists.
Edit: more elaboration
Say we call
(deleteElement 3 '((1 2) (3 4)))
You turn this into
(deleteElementPos 3 1 '((1 2) (3 4))),
which falls into the last case of the cond, and you get
(cons (deleteElementAcc 3 1 '(1 2))
(deleteElementAcc 3 1 '((3 4))))
notice that currPos is wrong for the cdr of the list - it should be 3, not 1. You actually want your code to turn into
(cons (deleteElementAcc 3 1 '(1 2))
(deleteElementAcc 3 (+ 1 2) '((3 4))))
because (car List) has 2 elements in it.
So, you just need to change
(deleteElementAcc Pos CurrPos (cdr List))
into
(deleteElementAcc Pos (+ CurrPos (recursive-length (car List))) (cdr List))
and program recursive-length, which is a pretty simple function. It should count elements in sublists, so for example (recursive-length '((1 2) ((3)))) returns 3.
While solving this problem in just any way isn't particularly difficult, it is really non-trivial to solve it well. By well I mean both big O's and code complexity, just as well as handling of corner cases. I'm not sure this code will handle even improper lists, and it has parts that could be certainly reduced in verbosity, but, technically, it is there. It walks through the tree in exactly O(n), where n is the number of elements in the tree, and it uses O(n + 2 * (maximum depth)) space, i.e. it will use the memory already used by the tree and in addition the memory proportional to the maximum depth of the tree.
No attempt was made to identify cyclic lists or duplicates:
(defun remove-from-tree-linear (tree &rest positions)
(loop with node = tree
with nilcar = (gensym)
with positions = (sort (remove-duplicates positions) #'<)
with counter = 0
with copy = nil
with root = nil
with stack = nil
with backrefs = nil
while (or node stack) do
(cond
((null node)
(setf backrefs (cdr backrefs))
(when (car stack)
(setf copy (car backrefs)))
(setf node (car stack) stack (cdr stack)))
((consp (car node))
(if copy
(if (eq (car copy) nilcar)
(setf (car copy) (list nilcar)
copy (car copy)
(car backrefs) copy)
(setf (cdr copy) (list nilcar)
copy (cdr copy)
(car backrefs) copy))
(setf copy (list nilcar)
root copy))
(setf backrefs (cons copy backrefs))
(setf stack (cons (cdr node) stack)
node (car node)))
(t (if (and positions (= counter (car positions)))
(setf positions (cdr positions))
(if copy
(progn
(if (eq (car copy) nilcar)
(setf (car copy) (list (car node))
copy (car copy))
(setf (cdr copy) (list (car node))
copy (cdr copy)))
(setf (car backrefs) copy))
(setf copy (list (car node))
root copy
backrefs (list copy))))
(setf node (cdr node))))
(incf counter)
finally (return root)))
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)))
)