0
votes

Apologies for the total noob question, rather struggling to get started with Clojure.

I have a string "buy=1|sell=2|limit=3|stop=4" and I am trying to turn it into a map

:buy 1
:sell 2
:limit 3
:stop 4

so far I have

(require '[clojure.string :as str])
=> nil

(def line "buy=1|sell=2|limit=3|stop=4") 
=> #'user/line

(str/split line #"\|")
=> ["buy=1" "sell=2" "limit=3" "stop=4"]

now to split a second time i was thinking i wanted to map a function onto the seq, so something like

map (str/split #"\=") (str/split line #"\|")
=> ArityException Wrong number of args (1) passed to: string/split  clojure.lang.AFn.throwArity (AFn.java:429)

I am trying to pass a partially applied function but doubt I have the syntax correct. I am passing the delimiter as the first argument to the function, however the string to be split should be passed first, so that is definitely incorrect.

Any pointers on a more idiomatic way to do this gratefully received.

3
in your map call the first param must be a function, that allows for one parameter. so your attempt was not that far of: (map #(str/split % #"\=") (str/split line #"\|")) (note the #(..%...) - cfrick
exactly what i was missing, thanks! - ksc0pe

3 Answers

2
votes
(def s "buy=1|sell=2|limit=3|stop=4")

(partition 2 (clojure.string/split s #"[=|]"))

will give you

(("buy" "1") ("sell" "2") ("limit" "3") ("stop" "4"))

now we reduce into a {} and transform "1" in 1, and "buy" in :buy

(reduce (fn [acc [k v]] (assoc acc (keyword k) (Integer. v))) {} (partition 2 (clojure.string/split s #"[=|]")))

which gives you

{:stop 4, :limit 3, :sell 2, :buy 1}

probably not the best but straightforward and works.

1
votes

This is one way of doing it:

(def st "buy=1|sell=2|limit=3|stop=4")
(->> (clojure.string/split st #"\|")
     (map #(re-matches #"(.+)=(.+)" %))
     (map (fn [[_ key value]] [(keyword key) value]))
     (into {}))

Returns:

{:buy "1", :sell "2", :limit "3", :stop "4"}
1
votes

re-seq is your friend here....

(def s "buy=1|sell=2|limit=3|stop=4")
(->> s                                                                                                           
  (re-seq #"(\w+)=(\d+)")                                                                                     
  (map (fn [[_ k v]] [(keyword k) (Integer/parseInt v)]))                                                     
  (into {}))
;=> {:buy 1, :sell 2, :limit 3, :stop 4}