Why does Incanter lose column title when only querying one column? - clojure

When selecting two columns from a dataset, the result has the two given column titles as expected. But when only specifying one column, the one resulting column loses it's title, instead, it is titled "0":
This makes it hard to use $order or whatever in later steps that take column names.
That is, this will work
(with-data data
(->> ($ [:foo :bar])
($order [:foo] :asc)
(view)))
and this will fail
(with-data data
(->> ($ [:foo])
($order [:foo] :asc)
(view)))
Any ideas what is going wrong or what to do?

which version of Incanter are you using? This behavior was changed in recent versions, and at least 1.5.4 works correctly. But take into account that behavior of $ is different when you pass the column name as single element, and as vector:
incanter.main=> (def data (dataset [:foo :bar] [[:a :b] [:c :d]]))
#'incanter.main/data
incanter.main=> ($ :foo data)
(:a :c)
incanter.main=> ($ [:foo] data)
| :foo |
|------|
| :a |
| :c |

It sounds like you hit on the correct answer when you point out that in the single key case incanter simply returns a sequence. One way to get around this, though it could be a little less elegant is to simply request a second column and ignore the second result or put it into a sequence of maps after. Something only a little hackish like:
(map hash-map (repeat :key) result-seq)

Related

Access data from a Lazy Sequence

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.

How to add a record to an existing map?

I have a map obtained from running a sql query.
(defn print-info
[rs]
(doseq [req rs]
(let [rs1 req]
(println "rs1" rs1))))
(defn display-info
[uname]
(sql/with-connection
db
(sql/with-query-results rs
["Select * from user"]
(print-info rs))))
Now i have copied the result set into another map. Is there any way to add another record to this existing map and return this new map to another function ?
If you use the non-deprecated query syntax which was explained in your other question, you can use the :row-fn to manipulate each record in a resultset. A default row is a map, so if you use only functions that return a map (like in this case select-keys), you can just use assoc to add a new key-value pair to the map.
(query db ["select * from user"]
:row-fn #(assoc (select-keys % [:name]) :type :user))
Generally speaking when I want to make a fix to a record I'll use merge, which merges any number of maps in a left-to-right direction. Thus:
user=> (merge {:foo 1 :bar 2 :ban 3} {:bar 20} {:ban 300})
{:foo 1, :bar 20, :ban 300}
Although the assoc approach mentioned above also works, I find merge generally more useful and more flexible.
This applies to anything represented as a map, of course, not just records!
As an aside I'd strongly recommend using [Korma|http://sqlkorma.com/] for your database queries.

How to get specific data from a set that holds hashmaps in clojure by specifying keyword and value

How can I find the name "olle" by specifying :id and value of :id in
(def persons #{{:id 1 :name "olle"}
{:id 2 :name "anna"}})
I need to some function that would get the rows that match to be able to access the values and the keys.
I'm trying to implement SQL syntax in clojure, this is for a school assignment, so I don't need code, more like hints on how I should go about it. So far I know that the functions get-in and clojure.set/select could be used.
Ultimately, what I'm trying to achieve is this statement to be parsed and interpreted
select [name]
from persons
where id=1
->"olle"
This is what I've been testing with so far with no result
(persons :id 1 :name)
;=> :name "olle"
=> (clojure.set/select :id #{1})
#{}
=> (clojure.set/select odd? #{1})
#{1}
I've also played around with get-in, but still I have not managed to get the feel of moving around in the set and hash-maps within the set, so much that I can carry on with the coding, also I'm not sure if I need to define any grammar looking code in this assignment or if I can just do with writing algorithms?
First off, each definition is not a list, they are each a set where each element is a hash-map. Since this is an assignment, I won't provide the complete code, but I will say that your answer could make good use of group-by, get-in, and update-in.
Hint:
(clojure.set/select #(= 1 (:id %)) persons)
;=> #{{:name "olle", :id 1}}
(clojure.set/project *1 [:name])
;=> #{{:name "olle"}}
Presumably your assignment is asking you to come up with a macro transformation from a SQL-like DSL. So, you have two parts to figure out - First, how do I do this with normal functions? Second, how do I effect the transformation with macros?

Merge two lists of maps, combining the maps together on a specific key

I'm running two select statements against Cassandra, so instead of having a join I need to join them in code. Being relatively new to Clojure, I'm having a hard time doing this without resorting to really ugly nested loops. Furthermore, if table-b is missing a matching entry from table-a, it should add default table-b values.
The two selects each result in a list of maps (each "row" is one map). The id key is a UUID, not string.
Here's how the selects look if I def something with the same structure.
(def table-a (list {:id "105421db-eca4-4500-9a2c-08f1e09a35ca" :col-b "b-one"}
{:id "768af3f3-3981-4e3f-a93d-9758cd53a056" :col-b "b-two"}))
(def table-b (list {:id "105421db-eca4-4500-9a2c-08f1e09a35ca" :col-c "c-one"}))
I want the end result to be this:
({:id "105421db-eca4-4500-9a2c-08f1e09a35ca" :col-b "b-one" :col-c "c-one"}
{:id "768af3f3-3981-4e3f-a93d-9758cd53a056" :col-b "b-two" :col-c "default-value"})
Thanks for any help.
This can be done by splitting it into groups with the same key, merging all the like-keyed maps and then filling in the default values:
user> (->> (concat table-a table-b) ;; stat with all the data
(sort-by :id) ;; split it into groups
(partition-by :id) ;; by id
(map (partial apply merge)) ;; merge each group into a single map.
(map #(assoc % ;; fill in the missing default values.
:col-c (or (:col-c %) "default value")
:col-b (or (:col-b %) "default value"))))
({:col-c "c-one",
:col-b "b-one",
:id "105421db-eca4-4500-9a2c-08f1e09a35ca"}
{:col-c "default value",
:col-b "b-two",
:id "768af3f3-3981-4e3f-a93d-9758cd53a056"})
Using the thread-last macro ->> makes this a lot easier for me to read, though that is just my opinion. There is also likely a more elegant way to supply the default keys.

clojure: how to get values from lazy seq?

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.