views:

299

answers:

2

I want to find the price of a new-item based on the average prices of similar items. The function get-k-similar uses k-Nearest Neighbors but returns me this output ((list rating age price) proximity).

For example, 2-similar would be:
(((5.557799748150248 3 117.94262493533647) . 3.6956648993026904)
 ((3.0921378389849963 7 75.61492560596851) . 5.117886776721699))

I need to find the average PRICE of the similar items. i.e Average of 117 and 75. Is there a better way to iterate? My function looks too ugly.

(define (get-prices new-item)

  (define (average-prices a-list)
    (/ (cdr 
        (foldl (λ(x y) (cons (list 0 0 0)
                             (+ (third (car x)) (third (car y))))) 
               (cons (list 0 0 0) 0)
               a-list))
        (length a-list)))

    (let ((similar-items (get-k-similar new-item)))
      (average-prices similar-items)))
+3  A: 

Common Lisp

(/ (reduce '+ a-list :key 'caddar) (length a-list))

or

(loop for ((nil nil e) . nil) in a-list
      count e into length
      sum e into sum
      finally (return (/ sum length)))
Rainer Joswig
+2  A: 

You can do the simple thing and just pull out every third value:

(define (average-prices a-list)
  (/ (apply + (map fourth a-list)) (length a-list)))

This is a little inefficient since it builds an intermediate list, and my guess is that this is why you tried foldl. Here's the right way to do that:

(define (average-prices a-list)
  (/ (foldl (lambda (x acc) (+ (third x) acc)) 0 l)
     (length a-list)))

There is still a minor inefficiency -- length is doing a second scan -- but that's something that you shouldn't bother about since you'd need some really long lists to get any visible slowdown.

Eli Barzilay
You brought up an interesting point. Can I accumulate the length of the list as I add the items?
kunjaan
Yes, of course -- in several ways, both imperative and functional. But at this stage I wouldn't bother about it if I were you.
Eli Barzilay