jbrown
jbrown

Reputation: 7986

How to call 2 sequential functions in clojure?

I'm trying to do exercise 20 on https://iloveponies.github.io/120-hour-epic-sax-marathon/recursion.html. Here's my code:

(defn my-frequencies-helper [freqs a-seq]
  (let [first-elem (first a-seq)
        rest-of-seq (rest a-seq)]
    (if (nil? first-elem)
      freqs
      (if (contains? freqs first-elem)
        (assoc freqs first-elem (inc (get freqs first-elem)))
        (assoc freqs first-elem 1)))))

(defn my-frequencies [a-seq]
  (my-frequencies-helper {} a-seq))

The problem is that this is not recursive. Somehow I need to add the following line into my-frequencies-helper after updating the freqs map:

(my-frequencies-helper freqs rest-of-seq)

Since it isn't dependent on a branch of an if function, I can't see how to do it without adding too many parameters to the if functions. I.e. it doesn't fit a cond or if because it's a step I want to call after doing another, functionally unrelated step.

I've probably got it wrong, but imperatively I just want to recursively call my-frequencies-helper after updating the map, i.e. in python something like:

freqs[first-elem] = freqs[first-elem] + 1
my-frequencies-helper(freqs, rest-of-seq)          # just another step to execute

How can I lever this into my code (or more likely, what would be another simple way to approach this)?

Upvotes: 2

Views: 206

Answers (2)

noisesmith
noisesmith

Reputation: 20194

We can simplify this code quite a bit with the help of destructuring:

(defn my-frequencies-helper
  [freqs [first-elem & rest-of-seq :as a-seq]]
    (if (empty? a-seq)
      freqs
      (let [updated-freqs (if (contains? freqs first-elem)
                            (assoc freqs first-elem (inc (get freqs first-elem)))
                            (assoc freqs first-elem 1))]
        (my-frequencies-helper updated-freqs rest-of-seq))))

Furthermore there is a common idiom for

(if (contains? freqs first-elem)
  (assoc freqs first-elem (inc (get freqs first-elem)))
  (assoc freqs first-elem 1))

The following is equivalent, as long as you would not store nil in the place of one of the numbers:

(update-in freqs [first-elem] (fnil inc 0))

This leaves us with the following simplified function:

(defn my-frequencies-helper
  [freqs [first-elem & rest-of-seq :as a-seq]]
    (if (empty? a-seq)
      freqs
      (my-frequencies-helper (update-in freqs [first-elem] (fnil inc 0)) rest-of-seq)))

Upvotes: 4

Shlomi
Shlomi

Reputation: 4748

For each item in the list, you'd want to look up in the result dictionary, to see if that item is already there, if so, you'd save it +1, if not, just store 1 in that dictionary.

with this you could solve it with a simple recursion, or use reduce.

Spoiler:

(defn my-frequencies [x] (reduce(fn[t n](assoc t n (inc(get t n 0)))) {} x))

Upvotes: 0

Related Questions