Maps and keywords in clojure - clojure

So I do my query on my posts for their eid and I get a list:
(map :eid (get-all-posts))
(17592186045421 17592186045438 17592186045440 17592186045540
17592186045545 17592186045550 17592186045588 17592186045590
17592186045592 17592186045594 17592186045597 17592186045608
17592186045616 17592186045721 17592186045866 17592186046045
17592186046047 17592186046075 17592186046077 17592186046079
17592186046081 17592186046083 17592186046085 17592186046088
17592186046149 17592186046158 17592186046170 17592186046174
17592186046292 17592186046352 17592186046362 17592186047146
17592186047211)
Every post can have many :ratings,
(get-all-ratings 17592186047211)
({:rating "positive",
:rid 17592186047652,
:email "vaso#ph"}
{:rating "positive",
:rid 17592186047756,
:email "sova.kua#gmcom"}
{:rating "meh",
:rid 17592186047725,
:email "badger#ton"})
Would like to combine the maps so I can `(count) the number of ratings per post.
(count (get-all-ratings 17592186047211)
3
But trying something like
(count (map get-all-ratings (map :eid (get-all-posts)))
simply returns the number of posts... it's a big list like
(({:rating "plus", :rid 7175 ..}
{:rating "plus" :rid 7374})
({:rating "whatever", :rid 7535})
()
() <some have no ratings
({:rating "green", :rid 7152}))
How can I tally up the number of times :rating shows up in a list of listed maps like above?
>(map :rating (map first (map get-all-ratings (map :eid (get-all-posts)))))
is something I've been playing with, and it returns a list, but as you can probably tell, it just returns one :rating field from each post's expanded ratings map.
Edit:
I noticed just now that something like
({:rating 5}
{:rating 3}
{:rating 7})
just becomes
{:rating 7}
...disregarding other entries in the list. How come?

Related

Batch Processing of Select query in clojure

I have a clojure application. It accepts a POST request with the following payload.
[
{
"key1": value1,
"key2": value2,
"key3": value3,
"key4": value4
},
{
"key1": value1,
"key2": value2,
"key3": value3,
"key4": value4
}
]
For each element of the array we make a SELECT call to DB using jdbc like so
(defn my-definition [db payload]
(->> payload
(map (fn [p]
(if-let [da (my-db-call-method db)]
(assoc da :key1 (:key1 p))
{:key2 (:key2 p)
:key3 (:key3 p)
})))))
DB call
(defn my-db-call-method [db json-params]
(with-sql-handling "my-db-call-method"
(jdbc/query db [my-query
(to long (:key1 json-params))
(to long (:key2 json-params))
)))
my-query.txt would look something like belowSelect * from my_table where col_name1 = ? and col_name2 =? Now, if 1 DB call takes 100 ms then 100 batch size would take 10 sec. This is too long. Is there a way to batch process the request in Clojure? Please note that code is in working condition but taking a long time due to sequential processing. How can we parallel process this? Can we use any third-party library to achieve this?

How do you control Z-order of entities in Seesaw(clojure)?

I have a window with an xyz-panel that holds a bunch of labels. Now some of them have to overlap and I can't figure out how to set the Z-order.
(defn- mk-smhi-frame
"create the frame"
[]
(sc/window
:width 1920
:height 1080
:content
(sc/xyz-panel :items [
; begin snip
(sc/label :id :clock
:bounds [1000 0 920 500]
:paint draw-clock)
;----------------------------------------------
; how do make :radar be on top of :clock?
;----------------------------------------------
(sc/label :id :radar
:bounds [1200 100 500 300]
:paint draw-radar)
; end snip
])))

How to idiomatically print currency in Clojure?

I'm using the following:
(defn dollars [input] (str "$" (format "%.2f" input)))
(which doesn't do the commas)
But I think there must be a method using pprint/cl-format.
My question is: How to idiomatically print currency in Clojure?
If you have more to work with money, than just formatting it, you might consider using https://github.com/clojurewerkz/money (see the section Formatting), which wrapps joda-money. This not only covers formatting, but also other common problems like rounding.
user=> (mf/format (ma/amount-of mc/USD 10000))
"$10,000.00"
user=> (mf/format (ma/amount-of mc/USD 10000) java.util.Locale/GERMANY)
"USD10.000,00"
edit
You can pass the amount-of means of rounding. E.g.
user=> (mf/format (ma/amount-of mc/USD 10.111111111111111))
ArithmeticException Scale of amount 10.11111111111111 is greater than the scale of the currency USD org.joda.money.Money.of (Money.java:74)
user=> (mf/format (ma/amount-of mc/USD 10.111111111111111 (java.math.RoundingMode/HALF_DOWN)))
"$10.11"
See also Bankster: https://github.com/randomseed-io/bankster
(money/of :EUR 25)
; => #money[25.00 EUR]
(money/of 25 :EUR)
; => #money[25.00 EUR]
(money/of crypto/BTC 10.1)
; => #money/crypto[10.10000000 BTC]
(money/of BTC 10.1)
; => #money/crypto[10.10000000 BTC]
#money EUR
; => #money[0.00 EUR]
#money/crypto ETH
; => #money/crypto[0.000000000000000000 ETH]
#money[PLN 2.50]
; => #money[2.50 PLN]
#currency USD
; => #currency{:id :USD, :domain :ISO-4217, :kind :FIAT, :numeric 840, :scale 2}
(currency/symbol :USD)
; => "USD"
(currency/symbol :USD :en_US)
; => "$"
(currency/symbol :USDT)
; => "₮"
(currency/name :USDT)
; => "Tether"
(money/format #money[10 EUR])
; => "10,00 €"
(money/format #money[10 EUR] :en_US)
; => "€10.00"
(money/format #money[10 EUR] :pl {:currency-symbol-fn currency/name})
; => "10,00 euro"

Clojure EDN as a Code Generation Metadata source

New to Clojure and wondering how to use it to make other languages I program in easier.
One thing I would like to be able to do is use Clojure for code generation.
For example, given the input from a data file (EDN format) how should I (1) walk this structure or (2) push the data into an existing templating mechanism?
Data below would be for defining simple REST API so that you could generate Clients from it. Generate clients in multiple languages by using different templates.
(:restcall "GetAccountBalance"
{:method "GET" :path "account/balance"}
{:id int})
(:restcall "GetLastTransactions"
{:method "GET" :path "account/transactions"}
{:page int})
resulting code would be something like
public void GetAccountBalance(int id)
{
var input = new { id = id };
callIntoRestLibrary("GET", "account/balance", input);
}
public void GetLastTransactions(int page)
{
var input = new { page = page };
callIntoRestLibrary("GET", "account/transactions", input);
}
Note: my end goal would having these as System.Net.Http.HttpClient calls via C#, but also be able to translate these into JavaScript/Ajax calls also
You have several choices for templating with Clojure. One place to look is the Clojure Toolbox.
Here is an example with clostache, a small library (358 loc) implementation of mustache.
(ns so.core
(:require [clostache.parser :refer (render)]))
(def template "
public void {{restcall}}({{id}} id)
{
var input = new { id = id };
callIntoRestLibrary(\"{{method}}\", \"{{path}}\", input);
}")
(def data
{:restcall "GetAccountBalance"
:method "GET" :path "account/balance" :id "int"})
(print (render template data))
Output:
public void GetAccountBalance(int id)
{
var input = new { id = id };
callIntoRestLibrary("GET", "account/balance", input);
}
To clear up confusion about what it means to read EDN.
(spit "foo.txt" (prn-str data))
Now the file foo.txt contains a textual representation of data, presumably your starting point.
(def data2 (with-open [r (java.io.PushbackReader. (java.io.FileReader. "foo.txt"))]
(clojure.edn/read r)))
(= data data2) ;=> true
So, read doesn't just pull in text, but also parses it into its data representation.

Specify Column and Row of a String Search

Because I'm working with a very complex table with nasty repeated values in variable places, I'd like to do a string search between specific rows and columns.
For example:
table={{"header1", "header2", "header3",
"header4"}, {"falsepositive", "falsepositive", "name1",
"falsepositive"}, {"falsepositive", "falsepositive", "name2",
"falsepositive"}, {"falsepositive", "falsepositive",
"falsepositive", "falsepositive"}}
%//TableForm=
header1 header1 header1 header1
falsepositive falsepositive name1 falsepositive
falsepositive falsepositive name2 falsepositive
falsepositive falsepositive falsepositive falsepositive
How do I look for a string, for example, in column three, rows one through two?
I'd like to use Which to assign values based on a string's location in the table.
E.g.,
Which[string matched in location one, value, matched in location two, value2]
As I understand it you want a test whether or not a given string is in a certain subsection of a matrix. You can pick these subsections using Part ([[...]]) and Span (;;), with which you can indicate ranges or subsamples of ranges. Testing whether or not this subsection contains your pattern can be done by MemberQ, like this:
MemberQ[table[[1 ;; 2, 3]], "name2"]
(* ==> False *)
MemberQ[table[[1 ;; 2, 3]], "header3"]
(* ==> True *)
In this way, your Which statement could look like this:
myVar =
Which[
MemberQ[table[[1 ;; 2, 3]], "name2"], 5,
MemberQ[table[[2 ;; 3, 4]], "falsepositive"], 6,
...
True, 20
]
Length[Cases[Position[table, "name1"], {1 | 2, 3}]] >= 1
Output -> True
Or
Cases[Position[table, "name1"], {1 | 2, 3}]
Output -> {{2, 3}}
Perhaps, if I understand you:
f[table_, value_, rowmin_, rowmax_, colmin_, colmax_] :=
Select[Position[table, value],
rowmin <= First## <= rowmax && colmin <= Last## <= colmax &]
f[table, "name1", 1, 10, 1, 10]
(*
-> {{2, 3}}
*)