Reputation: 6399
Not sure how to phrase the question, but, I'm just playing around with the twitter api and clojure as a part of my wanting to learn clojure.
I am not sure what the clojure way of approaching this problem
I am trying to get first 5 tweets of all my followers. I can get the list of followers with the api, and I have a list of follower screen_name
. Now, I have a function to get latest 5 tweets from a user. In C#, I would just declare a List<object>
and add tweets to it inside a for loop. Clojure doesn't quite work that way.. so here's what I'm trying to do:
(defn get-tweets
[follower]
{:text (str "I am " follower)
:favs 0})
(defn get-all-followers-tweets
[]
(let [followers ["a" "b" "c"]
followers-tweets (map #(get-tweets %) followers)]
followers-tweets))
These are just mockups, but, you get the idea. Now, twitter returns something like this: [{:text "ssd" :fav 1} {:text "fed" :fav 2}]
so when I call get-all-followers-tweets
, I get this:
(({:text "I am a", :favs 0}
{:text "I am b", :favs 0}
{:text "I am c", :favs 0}))
I don't know why the data is in 2 brackets, and I'm guessing it has something to do with map
but, I just need the :text
property from all collections.
doing (get response :text)
or (get-in response [:text])
returns nil
(assume response
is the collection)
So, How do I get all the :text
from the collection? Am I approaching this right? I tried (doseq [f followers] (get-tweets f))
and for
but they seem very unnatural for getting just all the tweets.
What's the ideal clojure way of doing this?
Upvotes: 1
Views: 273
Reputation: 3014
Your get-tweets
fn is returning a series of multiple maps, as a vector. You are then mapping that function over your followers, producing a sequence of sequences of maps. That's why there are two brackets - the outer sequence corresponds to the list of followers and each inner sequence is all the tweets from one follower grouped together.
I think the simplest approach if you're fine with discarding the identity of the authors is to use flatten
, a function for unravelling nested sequential data structures to get just the items. That will give you just a sequence of maps without any grouping. You can then map :text
over them to get just the texts.
e.g.
(defn get-all-followers-tweets
[]
(let [followers ["a" "b" "c"]
followers-tweets (map get-tweets followers)]
(flatten followers-tweets)))
(map :text (get-all-followers-tweets))
Maybe a more general solution is to consider mapcat
, which stands for map
-then-concat
. It's the go-to approach when you have
It does this by mapping the given function over the outer items to produce a bunch of sequences and then concatenates all those sequences into one. But in this case our "unpacking function" is itself map
so I don't think this approach is necessarily clearer here. That just makes it a little difficult to keep the different levels in mind:
(mapcat (partial map :text) (get-all-followers-tweets))
Upvotes: 1