This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-10-27
Channels
- # announcements (13)
- # asami (12)
- # babashka (65)
- # beginners (62)
- # calva (14)
- # cider (8)
- # clara (11)
- # clj-kondo (16)
- # clojure (86)
- # clojure-europe (12)
- # clojure-gamedev (4)
- # clojure-nl (2)
- # clojure-sg (4)
- # clojure-uk (5)
- # clojurescript (206)
- # clojureverse-ops (11)
- # community-development (7)
- # conjure (12)
- # core-async (2)
- # core-logic (13)
- # cursive (49)
- # datalevin (1)
- # datomic (30)
- # deps-new (3)
- # duct (8)
- # events (5)
- # fulcro (10)
- # helix (5)
- # jobs (1)
- # klipse (5)
- # lsp (178)
- # luminus (1)
- # malli (8)
- # meander (3)
- # membrane (13)
- # missionary (1)
- # nrepl (5)
- # other-languages (4)
- # pedestal (4)
- # reitit (3)
- # releases (1)
- # reveal (27)
- # shadow-cljs (89)
- # tools-build (6)
- # tools-deps (11)
- # vim (2)
- # xtdb (64)
I think rewriting a function from kotlin to clojure might be an interesting way to compare, but it probably would be a better comparison if the idea behind the function was already known. One of the issues with this function (imho) is that the algorithm isn't readily apparent. It seems like it's something of the form (into {} (comp (map ..) (filter ..)) props)
, but it's kind of hard to tell. I'm sure it could be written more cleanly in clojure and probably in kotlin as well.
I think trying to rewrite a function from a known language into clojure is a good, honest effort. Albeit probably not the best way to start learning. It’s something everyone has to do at some point or other, and I know I was lost the first time I had to do it.
I don’t know kotlin, but here’s a translation anyway, if propertySources
was pure data. Probably not a perfect translation, but more to show (somewhat) idiomatic clojure.
;; update-vals will be added to the next clojure version, but for now:
(defn update-vals [f coll]
(reduce-kv (fn [m k v]
(assoc m k (map f v)))
{}
coll))
(defn- get-properties-by-prefix-from-source [prefix {:keys [name property-names]}]
(let [;; sets can be used as a function
is-env (#{"systemEnvironment" "systemProperties"} name)
check-prefix (fn [name]
(if is-env
(str/starts-with? (str/upper-case name)
(str/replace (str/upper-case prefix) "_" "."))
(str/starts-with? name prefix)))
to-key (fn [name] (let [name (if is-env
(str/replace name "_" ".")
name)]
(second (str/split name #"\."))))]
(->> property-names
(filter check-prefix)
;; This will give us a tuple like [key name]
(map (juxt to-key identity)))))
(defn get-properties-by-prefix [prefix property-sources]
(->> property-sources
reverse
(map #(get-properties-by-prefix-from-source prefix %))
(apply concat) ;; to flatten
;; To convert our list of tuples into a map
(group-by first)
(update-vals last)))
(get-properties-by-prefix
"hello"
;; I imagine that's what propertySources could look like if it was pure data
[{:name "systemEnvironment"
:property-names ["HELLO_ENV_PROPERTY" "FOO_ENV_PROPERTY"]}
{:name "configFile"
:property-names ["hello.config.property" "hello.config.asd"]}])
;; Output
;; => {"config" ("hello.config.property" "hello.config.asd"),
;; "ENV" ("HELLO_ENV_PROPERTY")}
I can follow this logic haha, and I think you might have gotten it, I was getting too confused by the substring things in the Kotlin one
Hello, I´ve been using core.match
and I want to know if I can set the "matching" rules dynamicaly?
Like
(m/match [11]
[(_ :guard #(> % 10))] 10
[(_ :guard #(> % 15))] 15
:else 20)
the (m/match [something] (create-dynamic-rules))
is that possible?I'm starting to learn how to use D3 from CLJS. Not a whole lot of experience using interop or D3 itself. I'm able to achieve my objective, but could someone please give me some pointers how I could improve my code?
(def data
[{:letter "A", :frequency 0.08167}
{:letter "B", :frequency 0.01492}
{:letter "C", :frequency 0.02782}
{:letter "D", :frequency 0.04253}
{:letter "E", :frequency 0.12702}
{:letter "F", :frequency 0.02288}])
(defn render-barchart [dom-node props]
(let [svg (-> d3 (.select dom-node))
data (clj->js props)
size 200
; every item should have the same width
; creates a fn that lets you translate the value into a position on x-axis
x (-> (d3/scaleBand)
; start with zero and go to top
(.rangeRound (into-array [0 size]))
(.padding 0.1)
(.domain (into-array js/String (map (fn [d] ^js/String (.-letter d)) data))))
; _ (prn (into-array js/String (map (fn [d] (.-letter d)) data)))
y (-> (d3/scaleLinear)
; which min and max value to map into chart
; add a little extra to max
(.domain (into-array [0 (+ 0.15 (apply max (map :frequency data)))]))
; start with max value since coords start at top left
(.range (into-array [size 0])))
color (d3/scaleOrdinal d3/schemeCategory10)
selection (-> svg
(.selectAll "rect")
(.data data #_(fn [d] (.-frequency d))))]
(-> selection
.enter
(.append "rect")
(.attr "width" (.bandwidth x))
(.attr "height" (fn [d] (- size (y (.-frequency d)))))
(.attr "x" (fn [d] (x ^js/String (.-letter d))))
(.attr "y" (fn [d] (y (.-frequency d))))
(.attr "fill" (fn [d] (color ^js/String (.-letter d)))))))
Hi I’m Niklas 👋 and I’m new to Clojure.
I wanted to start with using Clojure for my day to day calculations and often I copy some numbers from somewhere which are formatted either in a US (`###,###.###`) or German (`###.###,###`) notation and which can have other symbols like $ or €
in the string so I needed to convert those strings into proper numbers Clojure can work with.
I searched around and found not really something which solves my problem so I built the following, but now I’m wondering: is there a better way to do this?
(ns playground
(:import [java.text NumberFormat]
[java.util Locale]))
(defn nf-us?
"Checks if the number format is US or not."
[string]
(let [[_ fn _] (re-matches #"^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$" string)]
(if fn true false)))
(defn nf-de?
"Checks if the number format is GERMAN or not."
[string]
(let [[_ fn _] (re-matches #"^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$" string)]
(if fn true false)))
(defn clean-str
; Javascript: /[^\d,.-]/g - strip everything except numbers, dots, commas and negative sign
; How to do it:
"Cleans up a given integer string to leave only numbers, dots, commas and negative sign."
[s]
(apply str (re-seq #"[\d\,\.\-]+" s)))
(defn str->int
; Got it from:
; Locale/US -> 4,974,357.00
; Locale/GERMANY -> 4.974.357,00
"Converts a given string into an integer no matter the number format."
[string]
(let [cs (clean-str string)
nf (NumberFormat/getNumberInstance (cond
(nf_us? cs) (Locale/US)
(nf_de? cs) (Locale/GERMAN)
:else (throw (Throwable. "Unknown number format!"))))]
(.parse nf cs)))
This is how it behaves:
(comment
(str->int "4,974,357.1") ; -> 4974357.1
(str->int "-4.974.357,1$") ; -> -4974357.1)
I know that the function should probably be named str->float
or parse-str
or something like that. 😅
I’m especially concerned with the regex since that is not my strong suit and I got it from a solution for JavaScript. (https://www.codegrepper.com/code-examples/javascript/convert+string+with+dot+or+comma+as+decimal+separator+to+number+in+javascript)
you might like instaparse - provides the grammar parsing capabilities with just providing a string of a grammar (although the "removing characters that aren't in this set" might still be more straightforward with a regex or just filtering against a set)
Thank you @U013JFLRFS8 for the recommendation. I’ll look into it 👍 I’ve also seen https://github.com/lambdaisland/regal as an alternative to RegEx. :thinking_face:
@niklas.heer I'm not sure about "better" but there's a fact: regex sucks! I recently wrote a simple calculator program, and used Antlr4 (https://www.antlr.org) parser generator for parsing the string. It's a bit overkill, but you might want to take a look at it. Here's the source code: https://github.com/pouyacode/calculator-api Here's the live project: https://calc.pouyacode.net I'll be more than happy to help you build the parser for your specific task.
@niklas.heer this project is well-commented. But if you need any help regarding what I did or if you wanted to learn more about Antlr4, we can chat/videocall and talk about it.
@abbassi.pouya that looks interesting and thank you for your kind offer 🙂 I’ll have a look and if I need help understanding it I’ll take you up on the offer 🙏
I created a project with babashka but I want to move some code to it's own lib. I have a doubt on how to deploy this lib to allow to use as a external dependency.
@fredbene babaskha supports the same dep mechanism as clojure, but in bb.edn
instead of deps.edn
. You can simply use git deps to get started.
Thanks for giving some tip where I need to look.
This is probably a dumb question about git deps... but.. here goes... I see some projects I'd like to try and they say to try them to use like what borkdude says and lists something like
{:deps {org.your/your-library {:git/url "a url" :git/sha "..."}}}
But how do I know what the :git/sha
is ?@qmstuart you look up the most recent sha on github (or gitlab, etc.) or use a tagged sha
you can pass tags to :git/sha
?
HOw would I find it on this project? It has no releases and no tags https://github.com/hyperfiddle/rcf
as for picking a commit, just try to find one that looks stable 🤷
yea, not sure why they make it so hard to find the git history
I made a tool called neil
which can do this for you:
https://github.com/babashka/neil
neil add dep weavejester/medley :latest-sha true
cat deps.edn
:
{:deps {weavejester/medley {:git/url ""
:git/sha "d723afcb18e1fae27f3b68a25c7a151569159a9e"}}
:aliases {}}
I have a map with keys that are strings and I used map to turn them into keywords; is this the best way to do this?
(let [phonebook {"name" "daniel" "number" "123456789"}]
(into {} (map (fn [[k v]] {(keyword k) v}) phonebook)))
If you're using Clojure 1.11 Alpha 2, you can do (update-keys phonebook keyword)
Prior to that, I'd probably use reduce-kv
:
(let [phonebook {"name" "daniel" "number" "123456789"}]
(reduce-kv (fn [m k v] (assoc m (keyword k) v)) {} phonebook))
not because it's shorter but because it won't make a sequence and then reconstruct a hash map.(we're using Clojure 1.11 Alpha 2 in production, in case folks wonder about working with prerelease versions of Clojure)
Awesome! Thanks Sean
well, there's also http://clojure.github.io/clojure/clojure.walk-api.html#clojure.walk/keywordize-keys
oh that looks easy
it's not super fast as currently implemented, and will deep transform (which you don't need) but it matches your intent
The speed shouldn't be too big of an issue, all my maps are small and this will only happen occasionally
So I'm realizing that my phonebook is not actually a clojure map, but instead a java.util.LinkedHashMap
to retain insertion order?
It's the result of querying a graph database using the Ogre library
do you care about retaining the ordering?
no I don't
well several or maybe all of these should still work
you'll just get a clojure map at the end
Yep that's great for my purposes
Nope I'm retired now 😁
OK I just added an (into {} ... and now it's behaving like I expected! Thanks for the great help!
reduce-kv will not work on the LinkedHashMap in Clojure 1.10.x but will now also work as of 1.11.0-alpha2
the other two options (into, keywordize-keys) should work in both
dev=> (let [phonebook (doto (java.util.LinkedHashMap.) (.put "name" "daniel") (.put "number" "123456789"))]
#_=> (update-keys phonebook keyword))
{:name "daniel", :number "123456789"}
(@alexmiller that's correctly showing update-keys
works on a LinkedHashMap
? My Java is rusty 🙂 )Should work
Clojure 1.10.3
user=> (let [phonebook (doto (java.util.LinkedHashMap.) (.put "name" "daniel") (.put "number" "123456789"))]
(reduce-kv (fn [m k v] (assoc m (keyword k) v)) {} phonebook))
Execution error (IllegalArgumentException) at user/eval136 (REPL:2).
No implementation of method: :kv-reduce of protocol: #'clojure.core.protocols/IKVReduce found for class: java.util.LinkedHashMap
Indeed. I can see that I don't work with LinkedHashMap
s very much 🙂