Question

If create a chez scheme ex which makes SUM of all elements from lista_de_elemente

(define lista_de_elemente (list 2 4 1 12 32 3 34 12))

(define suma
    (lambda()
        (apply + lista_de_elemente)))

How do I make the sum of only elements greater than 10?

Was it helpful?

Solution 2

The general technique is to first form the list of elements you want to process. You already have this list. Then, you want to apply one or more transformations to the input list. In this case, we don't need to make any transformations. Then, you filter the list to only get elements that satisfy a certain condition. Finally, you apply operations that combine elements in the filtered list.

This general way of processing lists is described in SICP as

enumerate -> transform (map) -> filter -> accumulate

Now, in this case, we don't need to enumerate or map anything because we already have our input list as I mentioned earlier.

(define (filter predicate sequence) (cond
   ((null? sequence) '())
   (else (cond
   ((predicate (car sequence)) (cons (car sequence) (filter predicate (cdr sequence))))
   (else (filter predicate (cdr sequence)))))))



(define (accumulate op initial sequence) (cond
                   ((null? sequence) initial)
                   (else (op (car sequence) (accumulate op initial (cdr sequence))))))


(define (sum-list list) (accumulate + 0 (filter (lambda(x) (cond ((> x 10) #t) (else #f)))list)))


(sum-list (list 1 2 3 45 12))
;Output: 57

The predicate is just a condition that evaluates to true or false.

OTHER TIPS

I imagine you may want to generalize it a little so I made filter-sum such that you can do this:

#!r7rs                                ; #!r6rs for r6rs
(import (scheme)                      ; replace scheme with rnrs for r6rs
        (only (srfi :1) filter fold)) ; remove filter for r6rs

;; I renamed you list
(define *lista-de-elemente* '(2 4 8 10 12 14 16))

(define (suma)
  (define (>10? x)
    (> x 10))

  (filter-sum >10? *lista-de-elemente*)) 

(suma) ; ==> 42

Here are some possible versions of filter-sum. We have the straight forward recursive way:

(define (filter-sum predicate lst)
  (cond ((null? lst) 0)
        ((not (predicate (car lst))) (filter-sum predicate (cdr lst)))
        (else (+ (car lst) (filter-sum predicate (cdr lst))))))

But it's not very good since the order or the numbers are not important. We can do this tail recursively with an accumulator, here with a named let instead of an axillary procedure:

(define (filter-sum predicate lst)
  (let loop ((lst lst)(acc 0))
    (if (null? lst)
        acc
        (loop (cdr lst) 
              (if (predicate (car lst))
                  (+ acc (car lst))
                  acc)))))

Now such loops with tail recursion and an accumulator can be converted to a fold. You find fold in the SRFI-1 list library:

(define (filter-sum predicate lst)
  (fold (lambda (x acc)
          (if (predicate x)
              (+ acc x)
              acc))
        0
        lst))

Most of the code now is if you should add or not. With filter you can filter out so that every element in the fold can be added:

(define (filter-sum predicate lst)
  (fold + 0 (filter predicate lst)))

filter is also in the SRFI-1 List library. Now if you know your list of number above 10 is short.. Like a few hundreds you can totally change fold to an apply and it might even become a little faster, but you are making a restrictions on the length of the list. (Many scheme systems push arguments on a limited size stack while a fold will accumulate the list one element at the time.)

By using filter:

(define suma
  (lambda()
    (apply + (filter (lambda (e) (> e 10)) lista_de_elemente))))

BTW, suma should have the list as an argument:

(define suma
  (lambda(lst)
    (apply + (filter (lambda (e) (> e 10)) lst))))

(suma lista_de_elemente)

Add a function that returns a list by filtering out the numbers that are not greater than 10. Pass the return value of that to apply as you have.

(define (get-greater-than-ten lst)

  (define (helper in out)
    (if (null? in)
      out
      (if (> (car in) 10)
        (helper (cdr in) (append out (list (car in))))
        (helper (cdr in) out)))

  (helper lst `()))

Use it like:

(define suma
    (lambda()
        (apply + (get-greater-than-ten lista_de_elemente))))

If you want to retain a generalized suma, rather than defining a suma that incorporates the filter, you can instead define a suma that just sums, and then filter your list as you pass it as a parameter:

(define elems (list 2 4 1 12 32 3 34 12))

(define (suma lst)
  (apply + lst))

(suma (filter (lambda (x) (> x 10)) elems))

Now you've got your generalized sum, and you pass it only the portion of the original list that you intend to sum.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top