I am trying to retrieve data from a DB. The data is coming back in a lazy sequence. I can peek at the data in repl and it looks like this:
({:foo value1, :bar value2})
How can I get at this data? preferably, how can I turn it into a map? I've tried:
(doall sequence (get sequence :foo))
Which just returns nil. And
(apply hash-map user-settings)
which returns
llegalArgumentException No value supplied for key: {:foo value1, :bar value2} clojure.lang.PersistentHashMap.create (PersistentHashMap.java:77)
I am very new to clojure and have been stuck on this for way too long. Thanks in advance.
You already have a map, it just happens to be the only item in your list.
(def data (first '({:foo 123 :bar 456})))
(:foo data) ; => 123
Sometimes when you want to print lazy seq to see your data use into. For example if you want to see contents of a lazy vector use (into [] your-lazy-vector) or (into {} your-lazy-map).
You can do this uncool conversion within a println function or in a let. However, I recommend removing this kind of debugging aid before release or pull-request.
Lazy sequences are great, most of the time.
Related
I declared a map in clojure using
(def finalMap {})
I am appending values to it inside a function using assoc but they are not appending, the map is remaining empty. I think it is due to immutability, can I in some way make a global map mutable.The function is a recursive one and I am appending values each time the function is called.
(defn func [arg1 arg2]
;(map append inside let)
(dorun (for [i (range 0 index)]
(do
(func(arg1 arg2))))))
Can you help me with the correct way to do this?
If you want a mutable map then you should create an atom:
(def final-map (atom {}))
Also normally you would use assoc to add more key value pairs to it. However you will need to use swap! just to be able to call assoc:
(swap! final-map assoc :a "a value")
This will add a key/value pair where the key is the keyword :a and the value is the String "a value".
It might be good to view some other examples of using assoc. Realise that in the code above assoc is being called with the old value of final-map as its first argument, and returning the new value of final-map.
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?
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
a series of data items with some sort of internal structure.
that you want to "unpack" so that each produces one or more of the items you actually want.
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))
Iam new to clojure and need some help to get a value out of a lazy sequence.
You can have a look at my full data structure here: http://pastebin.com/ynLJaLaP
What I need is the content of the title:
{: _content AlbumTitel2}
I managed to get a list of all _content values:
(def albumtitle (map #(str (get % :title)) photosets))
(println albumtitle)
and the result is:
({:_content AlbumTitel2} {:_content test} {:_content AlbumTitel} {:_content album123} {:_content speciale} {:_content neues B5 Album} {:_content Album Nr 2})
But how can I get the value of every :_content?
Any help would be appreciated!
Thanks!
You could simply do this
(map (comp :_content :title) photosets)
Keywords work as functions, so the composition with comp will first retrieve the :title value of each photoset and then further retrieve the :_content value of that value.
Alternatively this could be written as
(map #(get-in % [:title :_content]) photosets)
A semi alternative solution is to do
(->> data
(map :title)
(map :_content))
This take advances of the fact that keywords are functions and the so called thread last macro. What it does is injecting the result of the first expression in as the last argument of the second etc..
The above code gets converted to
(map :_content (map :title data))
Clearly not as readable, and not easy to expand later either.
PS I asume something went wrong when the data was pasted to the web, because:
{: _content AlbumTitel2}
Is not Clojure syntax, this however is:
{:_content "AlbumTitel2"}
No the whitespace after :, and "" around text. Just in case you might want to paste some Clojure some other time.
How do I convert a clojure map into string, almost key value pair, as shown below:
Clojure data:
(def data { :starks "Winter is coming" :Lannisters "Hear me roar" })
I want to convert the above to
"starks" "winter is coming" "Lannisters" "hear me roar"
I don't want any identifiers / delimiters between but obviously "starks" should always be followed by "winter is coming"
I tried this:
(str (keys data) (vals data))
Which outputs this:
"(:starks :Lannisters)(\"Winter is coming\" \"Hear me roar\")"
Which is not what I want at all...
The map data keys and values are not always the same so it needs to be generic
there will always be just one level, as in, the value will not contain a nested map etc..
Edit
What I'm actually trying to do:
I am trying to index a few thousand Neo4j nodes with clojure. To help me with this task, I am using Neocons Clojure neo4j library.
According to the documentation, the add-to-index accepts properties and values like so:
(nn/add-to-index (:id node) (:name idx) "username" "joe")))
which is, in my above case, going to look like
(nn/add-to-index (:id node) (:name idx) "starks" "winter is coming" "Lannisters" "Hear me roar")))
now, I have my Node, I can access the node properties with (:data node) and that gives me a clojure map.
The property differs pretty much from node to node so I'm trying to figure out how to pass that map to the library in the way that it understands..
Marius Danila's answer got me almost there.
Doing
(map name (apply concat data))
still complains of the third parameter, as it has the braces around the result.
So, how can I achieve this?
Do I just have to write a whole lot of if-not blocks to construct the properties myself?
Thanks
This should do the trick:
(map name (apply concat data))
A map can be viewed as a sequence of key-value pairs, which in turn represented as arrays of 2 elements. We're concatenating the pairs and then we extract the name from the keywords and strings (for string this does nothing, for keywords it returns the bit without ':').
From the code you've posted, I'm guessing you would use this like so:
(apply nn/add-to-index (list* (:id node) (:name idx) (map name (apply concat data))))
The (nn/add-to-index ...) function simply accepts only four arguments. The node, index and one key/value pair. So you have too loop through your data like.
(doseq [[k v] data]
(nn/add-to-index (:id node) (:name idx) (name k) (clojure.string/lower-case v))))
Unlike the the str function in Clojure the add-to-index function is more limited and simply does not accept variable parameter lists.
You can use vector to have array like random access:
=> (def v (vec (map name (apply concat data))))
=> (v 0)
;"starks"
=> (v 1)
;"Winter is coming"
You could try the following:
=> (interleave (map name (keys data)) (vals data))
;; which returns ("starks" "Winter is coming" "Lannisters" "Hear me roar")
First, I assume each structure-specific sequences would have different ways to remove an item: Vectors could be by index, List could be remove first or last, Set should be passing of the actual item to remove, etc.
Second, I assume there are some methods for removal that are structure agnostic; they work on seq interface.
Since sequences are immutable in Clojure, I suspect what you're actually doing is making a cheap copy of the original, only without the original item. This means list comprehension could be used for removal, but I suspect it would be unnecessarily verbose.
Please give some idiomatic examples of the different ways to remove items from Clojure sequences.
There is no single interface for removing things from all of Clojure's data structure types, possibly because of the different performance characteristics.
(disj #{:foo :bar} :foo) ; => #{:bar}
(dissoc {:foo 1 :bar 2} :foo) ; => {:bar 2}
(pop [:bar :foo]) ; => [:bar]
(pop (list :foo :bar)) ; => (:bar)
These also work (returning a seq):
(remove #{:foo} #{:foo :bar}) ; => (:bar)
(remove #{:foo} [:foo :bar]) ; => (:bar)
(remove #{:foo} (list :foo :bar)) ; => (:bar)
This doesn't work for hash-maps because when you iterate over a map, you get key/value pairs. But this works:
(remove (fn [[k v]] (#{:foo} k)) {:foo 1 :bar 2}) ; => ([:bar 2])
Look at the Clojure reference for sequences. filter and remove are what you seek.
As an extension of Brian Carper's answer. It depends on what you will be doing with the result. If you are passing the result to something that wants to work on the entire set of data (ie to print it) It is idiomatic to make a seq and use filter or remove to solve the problem lazily. If on the other hand you are modifying the data structure to save for various later uses then creating a seq on it would loose its favorable update characteristics so in this case its better to use the update function specific to that data structure.