Maurits Rijk
Maurits Rijk

Reputation: 9985

Alternatives for converting list of nested maps to a map

I have the following working code to convert a list with nested maps (actually tweet data) to a map:

(defn filter
  "This function returns a map with the user as key, #followers as value"
  [raw-tweets]

  (let [users (map :user raw-tweets)
        names (map :name users)
        followers (map :followers_count users)]
    (zipmap names followers)))

Although this works as expected, I was wondering if there would be a more idiomatic way to do this in Clojure. Any alternatives?

Upvotes: 2

Views: 398

Answers (4)

amalloy
amalloy

Reputation: 91837

I don't like the (map (fn ...)) pattern - it's really just an ugly way to write a for comprehension. I'd write this as:

(into {}
      (for [{:keys [user]} raw-tweets]
        ((juxt :name :followers_count) user)))

Or this, which feels a little less natural to me but avoids inventing names for values you're just going to use once anyway.

(into {} (map (comp (juxt :name :followers_count) :user)
              raw-tweets))

Upvotes: 1

Alex Taggart
Alex Taggart

Reputation: 7825

What you have is fine, though you can build the map as you go by using reduce:

(defn user-followers [raw-tweets]
  (reduce #(assoc %1 (:name %2) (:followers_count %2))
    {} (map :user raw-tweets)))

Upvotes: 2

ponzao
ponzao

Reputation: 20934

I find @Daan's answer nice, but I'd add destructuring into the mix.

(defn filter-tweets
  "This function returns a map with the user as key, #followers as value"
  [raw-tweets]
  (into {} (map (fn [{{name :name follower-count :followers_count} :user}]
                  [name follower-count])
                raw-tweets)))

Upvotes: 1

Daan
Daan

Reputation: 1546

I'm only starting to learn clojure but I think this way might be a bit more idiomatic. It's an alternative in any case.

(defn filter
  "This function returns a map with the user as key, #followers as value"
  [raw-tweets]
  (into {} (map #(let [user (:user %)]
                   [(:name user) (:followers_count user)])
                raw-tweets)))

It maps over the raw tweets with a function that retrieves the user for each tweet and returns a vector with the name and followers count for that user. The into function takes two sequences and conjoins every element of the second one onto the first, which will turn the list of vectors into a map before it's returned from the filter function.

Upvotes: 1

Related Questions