I am writing a procedure which returns a list with all of the negative odd and positive
even integers removed (strings can stay), by using lambda in the primitive filter procedure. I also am avoiding using recursion, but that is what's stumping me.
What I have so far is:
(define (f2b lst)
(cond ((null? lst)'()) ; if the list is empty, return the empty list
((pair? (car lst)) ; if the current element isn't a list
(filter (lambda (x) (or (even? x) (positive? x))) (car lst))
(filter (lambda (x) (or (odd? x) (negative? x))) (car lst)))
(else (string? (car lst)) ;otherwise, if the current element is a string,
(car lst) ; then return that element
(f2b (cdr lst)))))
I'm also not sure how I can apply both of the filter procedures at the same time.
It's way simpler than that. All you have to do is filter the list. You just need the appropriate predicate.
When do you want to keep an element? You phrased it in terms of what you want to remove, so let's start with that. You want to remove if it's a negative odd or a positive even integer, and leave everything else in. It's easier to break it down into smaller functions.
(define (positive-even? x) (and (positive? x) (even? x)))
(define (negative-odd? x) (and (negative? x) (odd? x)))
(define (remove-num? x) (or (positive-even? x) (negative-odd? x)))
This defines whether to keep a number. But the list element might not be a number. So we
keep it if it's not a number, or if it doesn't match remove-num?:
(define (keep-element? x) (or (not (number? x)) (not (remove-num? x))
Then your function just has to call filter:
(define (f2b lst) (filter keep-element? lst))
Seems to work:
(f2b '(-4 -3 -2 -1 0 1 2 3 4 "a string" "another"))
=> (-4 -2 0 1 3 "a string" "another")
Here's how it would look as one big honkin' function:
(define (f2b lst)
(filter
(lambda (x)
(or (not (number? x))
(not (or (and (positive? x) (even? x))
(and (negative? x) (odd? x))))))
lst)
Personally, the nested or not or and gets a bit hard to read for my taste...
Ok, apparently you have nested lists. All you have to do here is map the result of the filter with a function which:
when given a list, returns (f2b lst)
otherwise, returns the element unchanged.
I will leave it as an exercise for you since, if you thought my function could possibly work on a nested list, clearly you have a lot of learning to do...
Related
I want to write a recursive function that checks the list and either returns true if the list is in ascending order or NIL otherwise. If the list is empty it is still true. I am completely new to Lisp, so its still very confusing.
(defun sorted (x)
(if (null x)
T
(if (<= car x (car (cdr x)))
(sorted (cdr x))
nil)))
The recursive version:
(defun sorted (list)
(or (endp list)
(endp (cdr list))
(and (<= (first list) (second list))
(sorted (cdr list)))))
The more idiomatic loop-based predicate accepting a :test argument:
(defun sortedp (list &key (test #'<=))
(loop for (a b) on list
while b
always (funcall test a b)))
The version accepting a :key; we only call the key function once per visited element:
(defun sortedp (list &key (test #'<=) (key #'identity))
(loop for x in list
for old = nil then new
for new = (funcall key x)
for holdp = T then (funcall test old new)
always holdp))
Some tests:
(loop for k in '(()
((1))
((1) (2))
((2) (1))
((1) (2) (3))
((3) (2) (1)))
collect (sortedp k :test #'> :key #'car))
=> (T T NIL T NIL T)
This one also works with other kinds of sequences:
(defun sortedp (sequence &key (test #'<=) (key #'identity))
(reduce (lambda (old x &aux (new (funcall key x)))
(if (or (eq old t)
(funcall test old new))
new
(return-from sortedp nil)))
sequence
:initial-value t))
The above test gives:
(T 1 NIL 1 NIL 1)
... which is a correct result thanks to generalized booleans.
If you are doing your homework (seems so), then the above answers are fine. If you are just learning Lisp, and don't have constraints about recursivity, then the following might give you a glimpse about the power of Lisp:
(defun sorted (l)
(or (null l) (apply #'< l)))
The first problem with your solution is the base case You need to stop not at the end of the list, but when looking at the last to elements, as you need to elements to do the comparison. Also the parens are missing in the call to (car x)
(defun sorted (list)
(if (endp (cddr list))
(<= (car list) (cadr list))
(and (<= (car list) (cadr list))
(sorted (cdr list)))))
Bare in mind that recursive solutions are discouraged in CL
I am trying to write a simple recursive definition in Scheme (LISP).
The goal is to count the number of atomic elements in a list and recursively count internal list atoms as well.
For example:
(num_items '((a b) c d))
should return:
4
because "a", "b", "c", and "d" are the four atomic elements in the lists/sub-lists.
My code so far is as follows:
(define (num_items X)
(cond
((null? X) 0)
(list? (car X) (+ (num_items(car X)) (num_items(cdr X))))
(else (+ 1 (num_items(cdr X))))
))
(display(num_items '((a b) c d)))
The error is thrown on the 4th line:
(list? (car X) (+ (num_items(car X)) (num_items(cdr X))))
As far as I can tell, the (num_items(car X)) recursion in the addition seems to be causing the error. If I replace that part of the line with a 1 for example to get:
(list? (car X) (+ 1 (num_items(cdr X))))
Then the code compiles and runs, but then it doesn't solve the problem.
I am using Compile Online to test/run my code. The error it throws is:
$gosh main.scheme
gosh: "error": pair required, but got a
A pair of parentheses are missing in the fourth line, try this:
(define (num_items X)
(cond
((null? X) 0)
((list? (car X)) (+ (num_items (car X)) (num_items (cdr X))))
(else (+ 1 (num_items (cdr X))))))
Other than that, the code is fine. Just a minor suggestion: don't close parentheses in a separate line, close them all at the end. Also, notice that you can replace list? with pair? (or cons?, depending on which one is available in your interpreter). This is cheaper than testing if the value is a list.
I have written this function to 'check' if the list contains only 2-elements pairs like these: ((1 2)(3 1)(6 2)) --- (sorted based on first elements & no repetition of 1st elements). But I am getting errors, can anyone please give an idea:
(define Bag?
(lambda setlist
(cond ((null? setlist) '())
((and (pair? (caar setlist)) (= (length (caar setlist)) 2)))
((> (caar setlist) 0) (< (caar setlist) (car (cdr (car setlist) ))))
(else(Bag? (cdr setlist))))
))
The list traversal doesn't look right. The lambda is incorrectly declaring its parameter, and the second condition is wrong, you're not advancing the recursion there.
It'd better to start from scratch. I'll give you a high-level solution in Racket stating what needs to be checked, it's up to you to rewrite it in terms of simpler procedures:
(define (bag? setlist)
(and (apply < (map car setlist))
(andmap (lambda (e) (and (pair? e) (= 2 (length e))))
setlist)))
The above verifies that the first-elements in each pair appear sorted in ascending order, and that each pair in the list contains exactly two elements.
I'm making a program that takes a list and a sum. If some of the numbers in the list add up to the sum, it returns true. Else, return false. It seems to be working for some cases but not for others. For example,
if I input this:
(numlist-sum '(5 9) 9)
It should return true because one of the numbers (9) equals the sum (9). But, for some reason, its returning false.
I can't figure out what the problem is. Help please?
(define (numlist-sum? ls sum)
(if (null? ls) #t
(if (and (null? (cdr ls)) (equal? (car ls) sum)) #t
(if (equal? (car ls) sum) #t
(if (equal? (cdr ls) sum) #t
(if (equal? (apply + (car ls) (cdr ls)) sum) #t
#f))))))
I'll give you some hints for solving this problem (looks like homework). First write a procedure that generates all the possible subsets of the list (e.g., the power set of the list). For example:
(powerset '(1 2 3))
=> '(() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))
With the above procedure in hand (and it's easy to find the algorithm, Google is your best friend), simply iterate over each of the sublists and sum its values:
(apply + '(2 3))
=> 5
If one of the sublists' sum equals the expected value, return #t. If none of the sums satisfy the expected value, return #f.
EDIT:
I forgot to mention, this is a well-known problem - it's the subset sum problem, which can be efficiently solved (at least, more efficiently than generating the power set) using dynamic programming. But I don't think that's the goal of this homework in particular.
Here is a solution that checks each element one by one and then recurses down the list if the first element isn't the sum.
(define (numlist-sum list sum)
(and (not (null? list))
(let ((head (car list)))
(cond ((number? head)
(or (= sum head)
(numlist-sum (cdr list) sum)))
((list? head)
(or (= sum (apply + head))
(numlist-sum (cdr list) sum)))
(else 'ill-formed-list)))))
Also, note that your code can be rewritten as:
(define (numlist-sum? ls sum)
(or (null? ls)
(if (and (null? (cdr ls)) (equal? (car ls) sum))
(equal? (car ls) sum)
(equal? (cdr ls) sum)
(equal? (apply + (car ls) (cdr ls)) sum)))
I'd say the use of '(if pred #t else ...) is a bit awkward and hides the true logic of the code.
I have been working on a call to accumulate which goes as follows:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
However when I try to square something by slecting it through filter the answer doesn't work. What I have so far is this:
(define (f2b items)
(accumulate (lambda (x y)
(cons (append
(map square (filter negative? (filter number? x))) x) y)) () items)
)
The Input I give is:
(f2a '(("sdas" 89) (-53 "sad")))
The output I get is:
((sdas 89) (2809 -53 sad))
I can't seem to get the negative number to go away.
It would be much easier to use filter and map. Filter is predefined but it looks like this.
(define (filter1 predicate sequence)
(cond
((null? sequence) null)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
map is also predefined, it just runs a function over a list.
This should be pretty simple to write, but incase you need help you should just write a lamdba for the predicate in filter.
Actually, the functionality you describe is not usually the job of an accumulator. Instead, squaring negative numbers in a list seems like the perfect job for something like a map.
First, let's do:
(define (make-positive x)
(if (and (number? x) (negative? x))
(square x)
x))
Now suppose we want to operate on a list called lst. If it was just a flat list, like '(1 "2" -5 -4 6), then we could just
(map make-positive lst)
Since we need to operate on lists which are nested two levels deep, we could do:
(map (lambda (x)
(map make-positive x))
lst)
If we wanted to operate on lists which are nested arbitrarily deep, we could do:
(define (nested-map fn elm)
(if (list? elm)
(map (lambda (x) (nested-map fn x)) elm)
(fn elm)))
(nested-map make-positive lst)
PS - we can define map like this:
(define (map fn lst)
(if (empty? lst)
'()
(cons (fn (car lst))
(map fn (cdr lst)))))