0
votes

I am a beginner to functional programming and Clojure programming language and I'm resorting to recur pretty much for everything. I have a dataset in csv, imported as a map. I have extracted the info I need to use as vectors. Each column is a vector [1 5 10 8 3 2 1 ...] and I want to calculate the mean of each column. I wrote the following function:

(defn mean
  "Calculate the mean for each column"
  ([columns]
   (mean columns []))
  ([columns
    means]
   (if (empty? columns)
     means
     (recur (rest columns)
            (conj means (float (/ (reduce + (first columns)) (count (first columns)))))))))

;; Calcule the mean for the following vectors
(mean [[1 2 3] [1 2 3] [1 2 3]])
; => [2.0 2.0 2.0]

Is this a functional way of solving this problem?

2

2 Answers

6
votes

I'd break it down a little farther and use map instead of for. I personally like having many, smaller functions:

(defn mean [row]
  (/ (apply + row) (count row)))

(defn mean-rows [rows]
  (map mean rows))

But this is the same general idea as @Alan's answer.

The way you're doing it is already considered "functional". It should be said though that while using recur is good, usually you can achieve what you need more easily using reduce, or at least map. These options eliminate the need for explicit recursion, and generally lead to simpler, easier to understand code.

1
votes

Here is a simple answer:

(defn mean
  "Calculate the mean of each column"
  [cols]
  (vec    ; this is optional if you don't want it
    (for [col cols]
      (/                      ; ratio of num/denom
        (reduce + col)        ; calculates the numerator
        (count col)))))       ; the number of items

(mean [[1 2 3] [1 2 3] [1 2 3]]) => [2 2 2]

If you haven't seen it yet, you can get started here: https://www.braveclojure.com/

I recommend buying the printed version of the book, as it has more than the online version.