I have a data set in the format
{:application "name1", :date "date1", :description "desc1"}
{:application "name1", :date "date2", :description "desc2"}
{:application "name2", :date "date1", :description "desc1"}
{:application "name2", :date "date2", :description "desc2"}
etc ...)
My goal is to create a sequence containing the maps for an individual application, as below.
{:application "name1", :date "date1", :description "desc1"}
{:application "name1", :date "date2", :description "desc2"}
I've tried a number of different ways to do this but can't seem to get any to work. My current thinking for how to do it is:
(let[
a (for [x data] (if (= (get x :application) "name1") x))
])
I know there is probably a simple solution to this, but I'm new to Clojure and I just can't figure it out.
Thanks in advance.
David
if you only want name1
(filter (comp #{"name1"} :application) data)
to sort by name
(group-by :application data)
Related
I'm a newbie to clojure and i'm trying to convert a messages that come in a particular format into another.
ie, i have to convert something like:
{
:image-url ["https://image.png"],
:topic "Some title",
:id "88ebaf91-a01d-4683-9aa7-629bb3ecea01",
:short-description "Some Description",
:mobile-deeplink "https://deeplink.com/link",
:partner-name "partner"}
Into something like
{
:title "Some title",
:id "88ebaf91-a01d-4683-9aa7-629bb3ecea01",
:content {
:url ["https://image.png"],
:description "Some Description",
:deeplink "https://deeplink.com/link",
:partner "partner"}}
So in effect, there is a combination of renaming keys and nesting the flat map
What I have done so far was something on the lines of:
(let [message-map {
:image-url :purl
:topic :title
:partner-name :partner
:short-description :description
:mobile-deeplink :deeplink}]
(defn- map-to-body
[message]
(-> message
(clojure.set/rename-keys message-map)
;;some sort of (assoc-in) <- this is where i need help in
)))
Combining assoc-in, a path conversion table, and reduce could be more self-describing and maintainable. You could choose to reduce over either the conversion table or the input message, whichever makes more sense for the data you have.
(defn transform [m]
(let [pp '([:image-url [:content :url]]
[:topic [:title]]
[:id [:id]]
[:short-description [:content :description]]
;; etc.
)]
(reduce
(fn [o [mk ok]]
(assoc-in o ok (get m mk)))
{}
pp)))
You could chain-assoc-in here, but I think you are easier off
using select-keys. select-keys lets you extract only the keys
from a map into a new map, you need. So you can select :id/:title for
the outer map and the rest to assoc to :content.
E.g.
(require 'clojure.set)
(defn transform
[message]
(let [message-map {:image-url :url
:topic :title
:partner-name :partner
:short-description :description
:mobile-deeplink :deeplink}
renamed (clojure.set/rename-keys message message-map)]
(assoc ; XXX
(select-keys renamed [:title :id])
:content (select-keys renamed [:url :description :deeplink :partner]))))
(def src {:image-url ["https://image.png"],
:topic "Some title",
:id "88ebaf91-a01d-4683-9aa7-629bb3ecea01",
:short-description "Some Description",
:mobile-deeplink "https://deeplink.com/link",
:partner-name "partner"})
(def tgt {:title "Some title",
:id "88ebaf91-a01d-4683-9aa7-629bb3ecea01",
:content {
:url ["https://image.png"],
:description "Some Description",
:deeplink "https://deeplink.com/link",
:partner "partner"}})
(assert (= (transform src) tgt))
I just started learning Clojure and I'd like to get two keywords from a vector of maps.
Let's say there's a vector
(def a [{:id 1, :description "bla", :amount 12, :type "A", :other "x"} {:id 2, :description "blabla", :amount 10, :type "B", :other "y"}])
And I'd like to get a new vector
[{"bla" 12} {"blabla" 10}]
How can I do that??
Thanks!
Assuming you want the :description and :amount separately, not maps that map one to the other, you can use juxt to retrieve both at the same time:
(mapv (juxt :description :amount) a)
;; => [["bla" 12] ["blabla" 10]]
If you actually did mean to make maps, you can use for instance apply and hash-map to do that:
(mapv #(apply hash-map ((juxt :description :amount) %)) a)
;; => [{"bla" 12} {"blabla" 10}]
You can use mapv to map over the source vector. Within the transform function you can destructure each map to extract the keys you want and construct the result:
(mapv (fn [{:keys [description amount]}] {description amount}) a)
(mapv #(hash-map (:description %) (:amount %)) a)
I have created a table "sampletable". I am trying to display the name of the columns. I tried adding the text but it still doesn't show the names.
(def sampletable
(seesaw/table :model
[:columns [{:key :name, :text "Name"} :likes]
:rows [["Bobby" "Laura Palmer"]
["Agent Cooper" "Cherry Pie"]
{:likes "Laura Palmer" :name "James"}
{:name "Big Ed" :likes "Norma Jennings"}]]))
Any help would be appreciated.
Try this
(require '[seesaw.table])
(def sampletable
(seesaw/table
:model (seesaw.table/table-model
:columns [{:key :name, :text "Name"} :likes]
:rows [["Bobby" "Laura Palmer"]
["Agent Cooper" "Cherry Pie"]
{:likes "Laura Palmer" :name "James"}
{:name "Big Ed" :likes "Norma Jennings"}])))
I have data in clojure which I have grouped by application into following format:
(["name1" [{:application "name1", :date "date1", :description "desc1"}
{:application "name1", :date "date2", :description "desc2"}]]
["name2" [{:application "name2", :date "date1", :description "desc1"}
{:application "name2", :date "date2", :description "desc2"}]]
... and so on)
I need to count the number of events for each application (i.e. the number of maps in each vector) and produce a list of maps in the format:
({:application "name1", :count 2} {:application "name2", :count2} ... etc )
I have the following code to produce a list of application names and a list of the counts for each application name but I am struggling with how to get them back into the format above.
(let[
application-list (map first group-by-app)
grouped-data (map second group-by-app)
count-list (map count grouped-data)]
Any help would be greatly appreciated.
Thanks in advance.
David
for offers a really succinct, but expressive way to do something with the elements of sequences to build up a new sequence. I'd certainly recommend it here.
(def group-by-app '(["name1" [{:application "name1", :date "date1", :description "desc1"}
{:application "name1", :date "date2", :description "desc2"}]]
["name2" [{:application "name2", :date "date1", :description "desc1"}
{:application "name2", :date "date2", :description "desc2"}]]))
(for [[application events] group-by-app]
{:application application, :count (count events)})
; => ({:application "name1", :count 2} {:application "name2", :count 2})
For completeness, however, it's worth noting that map can map a function over multiple sequences at the same time. So, you could recombine the intermediate data you produced with a function of the application and the count.
(let [application-list (map first group-by-app)
grouped-data (map second group-by-app)
count-list (map count grouped-data)]
(map
(fn [app event-count]
{:application app :count event-count})
application-list count-list))
group-by produces a map, which is a sequence of key value pairs. You can simply map that sequence.
user=> (def foo #{{:application "name1", :date "date1", :description "desc1"}
#_=> {:application "name1", :date "date2", :description "desc2"}
#_=> {:application "name2", :date "date1", :description "desc1"}
#_=> {:application "name2", :date "date2", :description "desc2"}})
#'user/foo
user=> (map #(let [[key tuples] %] [key (count tuples)]) (group-by :application foo))
(["name1" 2] ["name2" 2])
You can turn that back into a map if that's what you need.
user=> (into {} (map #(let [[key tuples] %] [key (count tuples)]) (group-by :application foo)))
{"name1" 2, "name2" 2}
(reduce
(fn [acc [_ maps]]
(let [c (count maps)]
(into acc
(map #(assoc % :count c) maps))))
'()
grouped)
grouped is the grouped data you provided.
I am trying out clojure elastic search API Elastisch.
I was following the demo code given in the documentation
I am getting document/index created output for the following code
(defn demo-search-connect []
(esr/connect! "http://127.0.0.1:9200")
(let [mapping-types {:person {:properties {:username {:type "string" :store "yes"}
:first-name {:type "string" :store "yes"}
:last-name {:type "string"}
:age {:type "integer"}
:title {:type "string" :analyzer
"snowball"}
:planet {:type "string"}
:biography {:type "string" :analyzer "snowball" :term_vector "with_positions_offsets"}}}}
doc {:username "happyjoe" :first-name "Joe" :last-name "Smith" :age 30 :title "Teh Boss" :planet "Earth" :biography "N/A"}]
(esi/create "myapp2_development" :mappings mapping-types)
;; adds a document to the index, id is automatically generated by ElasticSearch
;= {:ok true, :_index people, :_type person, :_id "2vr8sP-LTRWhSKOxyWOi_Q", :_version 1}
(println (esd/create "myapp2_development" :person doc :settings {"number_of_shards" 1}))
))
;Supposed to return an output for the search query
(defn demo-search-index []
(esr/connect! "http://127.0.0.1:9200")
(esd/search "myapp2_development" "person" :query {:term {:last_name "Smith"}})
)
;Supposed to return the document with the given id
(defn get-document [id]
(esr/connect! "http://127.0.0.1:9200")
(esd/get "myapp2_development" "person" id)
)
I am getting the output for the first function as :
{:ok true, :_index myapp2_development, :_type :person, :_id GzNdzrqhQECQDlkSbq-GHA, :_version 1}
From the output I believe the document is getting indexed properly
The issue is that the second and third functions returns:
{:took 153, :timed_out false, :_shards {:total 5, :successful 5, :failed 0}, :hits {:total 0, :max_score nil, :hits []}}
and nil respectively.
What am I missing here?
P.S : I am new to clojure and elastic search
esd/get fails because your mapping type is :person not "person" (keyword vs. string).
Your code esd/search has the same problem, but in addition you should change last_name to last-name and by lower casing "Smith" to "smith" everything should work.