Given a list L=(M,A1,A2,...,An). Find sublist if they exist L1=(Ai,Ai+1,...,Ai+k), i+k<=N, i>=1, for which M=Ai+Ai+1+...Ai+k
For example: L=(1 3 -16 5 7 8 2 2), M=12
Result: L1=(1 3 -16)
L1=(5 7)
L1=(8 2 2)
for 5+7=12, 1+3-16=12, 8+2+2=12
How to solve this in lisp?
First try
Let's try to find one sublist first.
Sum = 10
List = (2 4 3 3 1)
What if you tried to recurse? List is (2 . (4 3 3 1)), subtract 2.
Sum = 8
List = (4 3 3 1)
Again:
Sum = 4
List = (3 3 1)
Again:
Sum = 1
List = (3 1)
Finally:
Sum = -2
List = (1)
We failed, because the sum is negative.
Discard the first element
We try again, but this time we skip the first element:
Sum = 10
List = (4 3 3 1)
... etc.
Sum = 0
List = (1)
Now we succeed, because the sum is zero, and we did not reach an empty list.
Hints and questions
we need to try all possible starting positions by skipping some N first elements;
we can recurse to solve sub-problems, while decreasing the sum;
there are different base cases, with the sum as well as the list;
when the sum is zero, it means we iterated over the sublist we looked for;
we need to somehow collect that sublist, where could we build it?
how do we collect all the possible sublists?
My take, obfuscated
(d.... s...... (s.. l...)
(l.....
((s...... (s.. l... r.....)
(c...
((m..... s..) n..)
((z.... s..) (l... (n....... r.....)))
((c.... l...) (d............-.... (h... . t...) l...
(s...... (- s.. h...) t... (l...* h... r.....))))
(t n..))))
(m..... (l..... (l...) (s...... s.. l... n..)) l...)))
Solution:
(setq l '(6 1 2 3 4 5 6 7 -1))
(setq comb nil)
(setq rez nil)
(defun sublist (lst)
(secondfunction (car lst) (cdr lst))
)
(defun secondfunction (head other)
(run (cdr other) (cdr other) (list(car other)) (list(list(car other))))
(final comb head nil)
)
(defun final (lst el result)
(if (>(length lst) 0)
(progn
(if(eq(loop for x in (car lst) sum x) el) (final (cdr lst) el (append result (cons (car lst) nil)))
(if(>(length lst) 0)(final (cdr lst) el result )))
)
(setq rez result)
)
)
(final comb (car l) nil)
(defun run (lst1 lst2 temp r)
(if (not(eq(car lst1) nil))
(if (not(eq(car lst2) nil))
(run lst1 (cdr lst2) (append temp (list (car lst2))) (append r (list (append temp (list (car lst2))))))
(run (cdr lst1) (cdr lst1) (list(car lst1)) (append r (list(list (car lst1)))))
)
(setq comb r)
)
)
(sublist l)
Related
I'm pretty new to lisp and I want to make function that every even-indexed element replace it with new one element list that holds this element. For example
(1 2 3 4 5) -> (1 (2) 3 (4) 5), (1 2 3 4 5 6) -> (1 (2) 3 (4) 5 (6))
Right now I came up with solution that each of the lements put in it's own list, but I cant get exactly how to select every even-indexed element:
(DEFUN ON3 (lst)
((ATOM (CDR lst)) (CONS (CONS (CAR lst) NIL) NIL))
(CONS (CONS (CAR lst) NIL) (ON3 (CDR lst))))
Your code doesn't work. You'll need to use if or cond such that the code follow one of the paths in it. Right now you have an error truing to call a function called (atom (cdr lst)). If it had been something that worked it would be dead code because the next line is always run regardless. It is infinite recursion.
So how to count. You can treat every step as a handle on 2 elements at a time. You need to take care of the following:
(enc-odds '()) ; ==> ()
(enc-odds '(1)) ; ==> (1)
(enc-odds '(1 2 3 ...) ; ==> (1 (2) (enc-odds (3 ...))
Another way is to make a helper with extra arguments:
(defun index-elements (lst)
(labels ((helper (lst n)
(if (null lst)
lst
(cons (list (car lst) n)
(helper (cdr lst) (1+ n))))))
(helper lst 0)))
(index-elements '(a b c d))
; ==> ((a 0) (b 1) (c 2) (d 3))
For a non-recursive solution, loop allows for constructing simultaneous iterators:
(defun every-second (list)
(loop
for a in list
for i upfrom 1
if (evenp i) collect (list a)
else collect a))
(every-second '(a b c d e))
; ==> (A (B) C (D) E)
See http://www.gigamonkeys.com/book/loop-for-black-belts.html for a nice explanation of loop
(defun fizzbuzz(lst emptyList)
(if (= (mod (car lst) 3) 0)
(fizzbuzz (cdr lst) (append emptyList (list(append (car lst) '(fizz)))))
)
(if (= (mod (car lst) 5) 0)
(fizzbuzz (cdr lst) (append emptyList (list(append (car lst) '(buzz)))))
)
(if (and (= (mod (car lst) 3) 0) (= (mod (car lst) 5) 0))
(fizzbuzz (cdr lst) (append emptyList (list(append (car lst)
'(fizzbuzz)))))
)
(fizzbuzz (cdr lst) (append emptyList (car lst)))
)
(fizzbuzz '(1 2 3 4 5) '(0))
Keep in mind I am new. My professor wants us to practice recursion using lisp. The program is supposed to add numbers that arent divisible by 5 or 3 to a list.
Those that are divisible by 3 get inserted into the list like so (3 fizz). Those divisible by 5: (5 buzz). Those divisible by both (15 fizzbuzz). How would I return the new list from the function? Also why am I getting the error listed in the title of the post?
You are getting this error because of the last expression (fizzbuzz (cdr lst) (append emptyList (car lst))).
First round (fizzbuzz '(1 2 3 4 5) '(0)) becomes (fizzbuzz '(2 3 4 5) '(0 . 1)) and then it will try to do (append '(0 . 1) 2). append can handle dotted list and atom as last argument, but it cannot append a dotted list when not the last argument. What is it supposed to do with the 1?
Also know that you have no stop condition and the separate if is run unconditionally to the other if so for 15 it will first recurse in the first, then throw away that result. Then it will recurse in the second to just throw that value away as well. Then unconditionally it will recurse in the last. I'm pretty sure you would only want one of them to be called and you do that with if-elseif-else and the lisp version of that is cond:
(cond
(p1 c1) ; if p1 then c1
(p2 c2 c2b) ; elseif p2 then c2 and c2b (last expression becomes the result)
(p3 c3) ; elseif p3 then c3
(t a4)) ; else a4
I have a non-linear list. I need to find out the number of sub-lists at any level in the initial list, for which the sum of the numerical atoms at the odd levels, is an even number. The superficial level is counted as 1. I wrote something like:
(defun numbering (l level)
;counts the levels that verify the initial conditions
(cond
((null l) l)
((and (verify (sumlist l)) (not (verify level))) (+ 1 (apply '+ (mapcar#' (lambda (a) (numbering a (+ 1 level))) l))))
(T (apply '+ (mapcar#' (lambda (a) (numbering a (+ 1 level))) l )))
)
)
(defun verify (n)
;returns true if the parameter "n" is even, or NIL, otherwise
(cond
((numberp n)(= (mod n 2) 0))
(T f)
)
)
(defun sumlist (l)
;returns the sum of the numerical atoms from a list, at its superficial level
(cond
((null l) 0)
((numberp (car l)) (+ (car l) (sumlist(cdr l))))
(T (sumlist(cdr l)))
)
)
(defun mainNumbering (l)
; main function, for initializing the level with 1
(numbering l 1)
)
If I run "(mainnum '(1 2 (a b 4) 8 (6 g)))" I get the error: " Undefined function MAPCAR# called with arguments ((LAMBDA (A) (NUMEROTARE A #)) (1 2 (A B 4) 8 (6 G)))."
Does anyone know, what am I missing? Thanks in advance!
Well, that's true, there is no such function as mapcar#, it's just a typo, you missing space in this line:
(T (apply '+ (mapcar#' (lambda (a) (numbering a (+ 1 level))) l )))
It should be:
(T (apply '+ (mapcar #'(lambda (a) (numbering a (+ 1 level))) l )))
Here is a possible solution, if I have interpreted correctly your specification:
(defun sum(l)
(loop for x in l when (numberp x) sum x))
(defun test(l &optional (level 1))
(+ (if (and (oddp level) (evenp (sum l))) 1 0)
(loop for x in l when (listp x) sum (test x (1+ level)))))
(test '(1 2 (a b 4) 7 (6 2 g) (7 1 (2 (3) (4 4) 2) 1 a))) ; => 2
The function sum applied to a list returns the sum of all its numbers (without entering in its sublists).
The function test, for a list with an odd level, sum its numbers, and, if the result is even, add 1 to the sum of the results of the function applied to the sublists of l, 0 otherwise.
in numbering you should add the case when l is a number,so
(defun numbering (l level)
;counts the levels that verify the initial conditions
(cond
((null l) l)
((atom l)0)
((and (verify (sumlist l)) (not (verify level))) (+ 1 (apply '+ (mapcar #' (lambda (a) (numbering a (+ 1 level))) l))))
(T (apply '+ (mapcar #'(lambda (a) (numbering a (+ 1 level))) l )))
)
)
will resolve the problem
What I have to do is removing some elements from the list,the 1st,2nd,4th,8th,elements on positions power of 2.I figured out that the easyest way for me to solve this is to construct how the result list should look like without destroying the original list.Here's my code but it doesn't work yet,I'm getting a type error.I'm using contor to know with which element of the list I'm working with an counter to specify only the position from which the elements should be removed.My question is what am I doing wrong and how can it be fixed?
(defun remo(l)
(defparameter e ())
(setq contor 0)
(setq counter 0)
(dolist (elem l) (
(cond
(
((or (< (expt 2 contor) counter) (> (expt 2 contor) counter))
((push elem e) (setq contor (+ 1 contor))))
))
(setq counter (+1 counter))
)
)
(print e)
)
(defun remo (l)
(do ((power-of-2 1)
(counter 1 (1+ counter))
(result ())
(sublist l (cdr sublist)))
((null sublist) (nreverse result))
(if (= counter power-of-2)
(setq power-of-2 (* 2 power-of-2))
(push (car sublist) result))))
(remo '(1 2 3 4 5 6 7 8 9 10))
=> (3 5 6 7 9 10)
I already improved another of your attempts at https://stackoverflow.com/a/20711170/31615, but since you stated the real problem here, I propose the following solution:
(defun remove-if-index-power-of-2 (list)
(loop :for element :in list
:for index :upfrom 1 ; correct for language: "1st" is index 0
:unless (power-of-2-p index)
:collect element))
(defun power-of-2-p (number)
"Determines whether number, which is assumed to be a nonnegative
integer, is a power of 2 by counting the bits."
(declare (type (integer 0 *) number))
(= 1 (logcount number)))
Given a list, how would I select a new list, containing a slice of the original list (Given offset and number of elements) ?
EDIT:
Good suggestions so far. Isn't there something specified in one of the SRFI's? This appears to be a very fundamental thing, so I'm surprised that I need to implement it in user-land.
Strangely, slice is not provided with SRFI-1 but you can make it shorter by using SRFI-1's take and drop:
(define (slice l offset n)
(take (drop l offset) n))
I thought that one of the extensions I've used with Scheme, like the PLT Scheme library or Swindle, would have this built-in, but it doesn't seem to be the case. It's not even defined in the new R6RS libraries.
The following code will do what you want:
(define get-n-items
(lambda (lst num)
(if (> num 0)
(cons (car lst) (get-n-items (cdr lst) (- num 1)))
'()))) ;'
(define slice
(lambda (lst start count)
(if (> start 1)
(slice (cdr lst) (- start 1) count)
(get-n-items lst count))))
Example:
> (define l '(2 3 4 5 6 7 8 9)) ;'
()
> l
(2 3 4 5 6 7 8 9)
> (slice l 2 4)
(3 4 5 6)
>
You can try this function:
subseq sequence start &optional end
The start parameter is your offset. The end parameter can be easily turned into the number of elements to grab by simply adding start + number-of-elements.
A small bonus is that subseq works on all sequences, this includes not only lists but also string and vectors.
Edit: It seems that not all lisp implementations have subseq, though it will do the job just fine if you have it.
(define (sublist list start number)
(cond ((> start 0) (sublist (cdr list) (- start 1) number))
((> number 0) (cons (car list)
(sublist (cdr list) 0 (- number 1))))
(else '())))
Try something like this:
(define (slice l offset length)
(if (null? l)
l
(if (> offset 0)
(slice (cdr l) (- offset 1) length)
(if (> length 0)
(cons (car l) (slice (cdr l) 0 (- length 1)))
'()))))
Here's my implementation of slice that uses a proper tail call
(define (slice a b xs (ys null))
(cond ((> a 0) (slice (- a 1) b (cdr xs) ys))
((> b 0) (slice a (- b 1) (cdr xs) (cons (car xs) ys)))
(else (reverse ys))))
(slice 0 3 '(A B C D E F G)) ;=> '(A B C)
(slice 2 4 '(A B C D E F G)) ;=> '(C D E F)