I'm still new in Clojure; I'm trying to split the values parsed from CSV file but without using clojure.string/split lib or any other lib just clojure.core, please some help, thanks in advance.
you can accomplish the same result with re-seq and string/split
user> (clojure.string/split "a,b,c,d,e" #",")
["a" "b" "c" "d" "e"]
user> (re-seq #"[^,]+" "a,b,c,d,e")
("a" "b" "c" "d" "e")
Both of these are available with no dependencies so there is little reason not to use string/split in many cases.
parsing CSV is also a good choice if you are willing to add a dependency:
user> (require '[clojure.data.csv :as csv])
nil
user> (csv/read-csv "A,B,C\n1,2,3\n4,5,5")
(["A" "B" "C"] ["1" "2" "3"] ["4" "5" "5"])
If your hands were tied and couldn't use clojure.string or clojure.data.csv or re-seq or interop:
(defn comma-separate [s]
(->> s
(partition-by #{\,})
(take-nth 2)
(map #(apply str %))))
(comma-separate "foo,bar") ;; ("foo" "bar")
I agree that you should use clojure.string or clojure.data.csv
Related
(first ["a" "b" "c"])
->
"c"
where I would expect:
(first ["a" "b" "c"])
->
"a"
I think I must have misunderstood something here ,any help appreciated!
Best Regards.
(defn binnd-to-name [name-string to-bind]
(bind-to-name name-string to-bind))
(defmacro bind-to-name [name-string stuff-to-bind]
`(def ~(symbol name-string) ~stuff-to-bind))
(defn bind-services [list-of-services]
(if (empty? list-of-services)
nil
(do
(binnd-to-name (first (first list-of-services)) (last (first list-of-services)))
(bind-services (rest list-of-services)))))
(bind-services [["*my-service*" se.foo.bar.service.ExampleService]])
ExampleService is a Java class on the classpath, which I want to bind to the symbol my-service.
The idea is to loop through a list of name-value pairs and bind each name to the value.
It is not working as expected though.
So somehow in this code something evaluated into "def first last" apparently.
Problem is with your macros not expanding as you expect
(defmacro bind-to-name [name-string stuff-to-bind]
`(def ~(symbol name-string) ~stuff-to-bind))
(defmacro bind-services [services]
`(do
~#(for [s services]
`(bind-to-name ~(first s) ~(second s)))))
(bind-services [["*my-service*" se.foo.bar.service.ExampleService]])
If you try this approach your def symbol sequence will properly expand.
No way!
user=> (doc first)
-------------------------
clojure.core/first
([coll])
Returns the first item in the collection. Calls seq on its
argument. If coll is nil, returns nil.
user=> (first ["a" "b" "c"])
"a"
I would like to write a function replace-several that receives a string and a set of replacements and apply all the replacements (where the replacements see the result of the previous replacements).
I thought about the following interface:
(replace-several "abc" #"a" "c"
#"b" "l"
#"c" "j"); should return "jlj"
Two questions:
Is it the most idiomatic interface in clojure?
How to implement this function?
Remark: To make a single replacement, there is replace available in clojure.string.
Implementing #kotarak's advice using replace, reduce and partition:
(defn replace-several [content & replacements]
(let [replacement-list (partition 2 replacements)]
(reduce #(apply string/replace %1 %2) content replacement-list)))
; => (replace-several "abc" #"a" "c" #"b" "l" #"c" "j")
"jlj"
So you have replace, reduce and partition. From these building blocks you can build your replace-several.
Here is another shot but that has different output results, this one uses the regex engine features so it potentially may be faster, also the interface is different, since it maps keys to replacement strings. I provide this in case it may be useful to someone with a similar question.
(defn replace-map
"given an input string and a hash-map, returns a new string with all
keys in map found in input replaced with the value of the key"
[s m]
(clojure.string/replace s
(re-pattern (apply str (interpose "|" (map #(java.util.regex.Pattern/quote %) (keys m)))))
m))
So usage would be like so:
(replace-map "abc" {"a" "c" "b" "l" "c" "j"})
=> "clj"
I'm late to this party, but for what it's worth, I think the most idiomatic way to do this would be to use threading and multiple replacements:
(require '[clojure.string :refer [replace])
(-> "abc"
(replace #"a" "c")
(replace #"b" "l")
(replace #"c" "j"))
;=> "jlj"
The meaning of this is quite clear, though it is nice to avoid typing the "replace" multiple times.
(str/escape "abc" {\a "c" \b "l" \c "j"})
; => "clj"
Docs escape
You can use reduce with replace:
(defn replace-several
[str & replacements]
(reduce (fn [s [a b]]
(clojure.string/replace s a b))
str
(partition 2 replacements)))
(replace-several "abc"
#"a" "c"
#"b" "l"
#"c" "j")
Personally I wouldn't create a separate function for this, as it is just a composition of existing Clojure functions:
(reduce-kv clojure.string/replace "Hello" {#"[A-Z]" "J", "o" "y"}
;=> "Jelly"
Of course if you want varargs and an interface then:
Yes it seems reasonably idiomatic
I'd implement it thus:
(defn replace-many [string & {:as rplcmnts}]
(reduce-kv clojure.string/replace string rplcmnts))
first guess..
(defn replace-several [string & mappings]
(loop [grouped-mappings (partition 2 mappings) string string]
(if (empty? grouped-mappings)
string
(let [[re rep] (first grouped-mappings)]
(recur (rest grouped-mappings) (clojure.string/replace string re rep))))))
; => (replace-several "abc" #"a" "c" #"b" "l" #"c" "j")
"jlj"
If I have the request "size=3&mean=1&sd=3&type=pdf&distr=normal" what's the idiomatic way of writing the function (defn request->map [request] ...) that takes this request and
returns a map {:size 3, :mean 1, :sd 3, :type pdf, :distr normal}
Here is my attempt (using clojure.walk and clojure.string):
(defn request-to-map
[request]
(keywordize-keys
(apply hash-map
(split request #"(&|=)"))))
I am interested in how others would solve this problem.
Using form-decode and keywordize-keys:
(use 'ring.util.codec)
(use 'clojure.walk)
(keywordize-keys (form-decode "hello=world&foo=bar"))
{:foo "bar", :hello "world"}
Assuming you want to parse HTTP request query parameters, why not use ring? ring.middleware.params contains what you want.
The function for parameter extraction goes like this:
(defn- parse-params
"Parse parameters from a string into a map."
[^String param-string encoding]
(reduce
(fn [param-map encoded-param]
(if-let [[_ key val] (re-matches #"([^=]+)=(.*)" encoded-param)]
(assoc-param param-map
(codec/url-decode key encoding)
(codec/url-decode (or val "") encoding))
param-map))
{}
(string/split param-string #"&")))
You can do this easily with a number of Java libraries. I'd be hesitant to try to roll my own parser unless I read the URI specs carefully and made sure I wasn't missing any edge cases (e.g. params appearing in the query twice with different values). This uses jetty-util:
(import '[org.eclipse.jetty.util UrlEncoded MultiMap])
(defn parse-query-string [query]
(let [params (MultiMap.)]
(UrlEncoded/decodeTo query params "UTF-8")
(into {} params)))
user> (parse-query-string "size=3&mean=1&sd=3&type=pdf&distr=normal")
{"sd" "3", "mean" "1", "distr" "normal", "type" "pdf", "size" "3"}
Can also use this library for both clojure and clojurescript: https://github.com/cemerick/url
user=> (-> "a=1&b=2&c=3" cemerick.url/query->map clojure.walk/keywordize-keys)
{:a "1", :b "2", :c "3"}
Yours looks fine. I tend to overuse regexes, so I would have solved it as
(defn request-to-keywords [req]
(into {} (for [[_ k v] (re-seq #"([^&=]+)=([^&]+)" req)]
[(keyword k) v])))
(request-to-keywords "size=1&test=3NA=G")
{:size "1", :test "3NA=G"}
Edit: try to stay away from clojure.walk though. I don't think it's officially deprecated, but it's not very well maintained. (I use it plenty too, though, so don't feel too bad).
I came across this question when constructing my own site and the answer can be a bit different, and easier, if you are passing parameters internally.
Using Secretary to handle routing: https://github.com/gf3/secretary
Parameters are automatically extracted to a map in :query-params when a route match is found. The example given in the documentation:
(defroute "/users/:id" [id query-params]
(js/console.log (str "User: " id))
(js/console.log (pr-str query-params)))
(defroute #"/users/(\d+)" [id {:keys [query-params]}]
(js/console.log (str "User: " id))
(js/console.log (pr-str query-params)))
;; In both instances...
(secretary/dispach! "/users/10?action=delete")
;; ... will log
;; User: 10
;; "{:action \"delete\"}"
You can use ring.middleware.params. Here's an example with aleph:
user=> (require '[aleph.http :as http])
user=> (defn my-handler [req] (println "params:" (:params req)))
user=> (def server (http/start-server (wrap-params my-handler)))
wrap-params creates an entry in the request object called :params. If you want the query parameters as keywords, you can use ring.middleware.keyword-params. Be sure to wrap with wrap-params first:
user=> (require '[ring.middleware.params :refer [wrap-params]])
user=> (require '[ring.middleware.keyword-params :refer [wrap-keyword-params])
user=> (def server
(http/start-server (wrap-keyword-params (wrap-params my-handler))))
However, be mindful that this includes a dependency on ring.
I want to send var-args of a function to a macro, still as var-args.
Here is my code:
(defmacro test-macro
[& args]
`(println (str "count=" ~(count args) "; args=" ~#args)))
(defn test-fn-calling-macro
[& args]
(test-macro args))
The output of (test-macro "a" "b" "c") is what I want: count=3; args=abc
The output of (test-fn-calling-macro "a" "b" "c") is : count=1; args=("a" "b" "c") because args is sent as a single argument to the macro. How can I expand this args in my function in order to call the macro with the 3 arguments?
I guess I'm just missing a simple core function but I'm not able to find it. Thanks
EDIT 2 - My "real" code, shown in EDIT section below is not a valid situation to use this technique.
As pointed out by #Brian, the macro xml-to-cass can be replaced with a function like this:
(defn xml-to-cass
[zipper table key attr & path]
(doseq [v (apply zf/xml-> zipper path)] (cass/set-attr! table key attr v)))
EDIT - the following section goes beyond my original question but any insight is welcome
The code above is just the most simple I could come with to pinpoint my problem. My real code deals with clj-cassandra and zip-filter. It may also look over-engineering but it's just a toy project and I'm trying to learn the language at the same time.
I want to parse some XML found on mlb.com and insert values found into a cassandra database. Here is my code and the thinking behind it.
Step 1 - Function which works fine but contains code duplication
(ns stats.importer
(:require
[clojure.xml :as xml]
[clojure.zip :as zip]
[clojure.contrib.zip-filter.xml :as zf]
[cassandra.client :as cass]))
(def root-url "http://gd2.mlb.com/components/game/mlb/year_2010/month_05/day_01/")
(def games-table (cass/mk-cf-spec "localhost" 9160 "mlb-stats" "games"))
(defn import-game-xml-1
"Import the content of xml into cassandra"
[game-dir]
(let [url (str root-url game-dir "game.xml")
zipper (zip/xml-zip (xml/parse url))
game-id (.substring game-dir 4 (- (.length game-dir) 1))]
(doseq [v (zf/xml-> zipper (zf/attr :type))] (cass/set-attr! games-table game-id :type v))
(doseq [v (zf/xml-> zipper (zf/attr :local_game_time))] (cass/set-attr! games-table game-id :local_game_time v))
(doseq [v (zf/xml-> zipper :team [(zf/attr= :type "home")] (zf/attr :name_full))] (cass/set-attr! games-table game-id :home_team v))))
The parameter to import-game-xml-1 can be for example "gid_2010_05_01_colmlb_sfnmlb_1/". I remove the "gid_" and the trailing slash to make it the key of the ColumnFamily games in my database.
I found that the 3 doseq were a lot of duplication (and there should be more than 3 in the final version). So code templating using a macro seemed appropriate here (correct me if I'm wrong).
Step 2 - Introducing a macro for code templating (still works)
(defmacro xml-to-cass
[zipper table key attr & path]
`(doseq [v# (zf/xml-> ~zipper ~#path)] (cass/set-attr! ~table ~key ~attr v#)))
(defn import-game-xml-2
"Import the content of xml into cassandra"
[game-dir]
(let [url (str root-url game-dir "game.xml")
zipper (zip/xml-zip (xml/parse url))
game-id (.substring game-dir 4 (- (.length game-dir) 1))]
(xml-to-cass zipper games-table game-id :type (zf/attr :type))
(xml-to-cass zipper games-table game-id :local_game_time (zf/attr :local_game_time))
(xml-to-cass zipper games-table game-id :home_team :team [(zf/attr= :type "home")] (zf/attr :name_full))))
I believe that's an improvement but I still see some duplication in always reusing the same 3 parameters in my calls to xml-to-cass. That's were I introduced an intermediate function to take care of those.
Step 3 - Adding a function to call the macro (the problem is here)
(defn import-game-xml-3
"Import the content of xml into cassandra"
[game-dir]
(let [url (str root-url game-dir "game.xml")
zipper (zip/xml-zip (xml/parse url))
game-id (.substring game-dir 4 (- (.length game-dir) 1))
save-game-attr (fn[key path] (xml-to-cass zipper games-table game-id key path))]
(save-game-attr :type (zf/attr :type)) ; works well because path has only one element
(save-game-attr :local_game_time (zf/attr :local_game_time))
(save-game-attr :home :team [(zf/attr= :type "home"] (zf/attr :name_full))))) ; FIXME this final line doesn't work
Here's a some simple code which may be illuminating.
Macros are about code generation. If you want that to happen at runtime, for some reason, then you have to build and evaluate the code at runtime. This can be a powerful technique.
(defmacro test-macro
[& args]
`(println (str "count=" ~(count args) "; args=" ~#args)))
(defn test-fn-calling-macro
[& args]
(test-macro args))
(defn test-fn-expanding-macro-at-runtime
[& args]
(eval (cons `test-macro args)))
(defmacro test-macro-expanding-macro-at-compile-time
[& args]
(cons `test-macro args))
;; using the splicing notation
(defmacro test-macro-expanding-macro-at-compile-time-2
[& args]
`(test-macro ~#args))
(defn test-fn-expanding-macro-at-runtime-2
[& args]
(eval `(test-macro ~#args)))
(test-macro "a" "b" "c") ;; count=3; args=abc nil
(test-fn-calling-macro "a" "b" "c") ;; count=1; args=("a" "b" "c") nil
(test-fn-expanding-macro-at-runtime "a" "b" "c") ; count=3; args=abc nil
(test-macro-expanding-macro-at-compile-time "a" "b" "c") ; count=3; args=abc nil
(test-macro-expanding-macro-at-compile-time-2 "a" "b" "c") ; count=3; args=abc nil
(test-fn-expanding-macro-at-runtime "a" "b" "c") ; count=3; args=abc nil
If contemplation of the above doesn't prove enlightening, might I suggest a couple of my own blog articles?
In this one I go through macros from scratch, and how clojure's work in particular:
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-i-getting.html
And in this one I show why run-time code generation might be useful:
http://www.learningclojure.com/2010/09/clojure-faster-than-machine-code.html
The typical way to use a collection as individual arguments to a function is to use (apply function my-list-o-args)
(defn test-not-a-macro [& args]
(print args))
(defn calls-the-not-a-macro [& args]
(apply test-not-a-macro args))
though you wont be able to use apply because test-macro is a macro. to solve this problem you will need to wrap test macro in a function call so you can apply on it.
(defmacro test-macro [& args]
`(println ~#args))
(defn calls-test-macro [& args]
(eval (concat '(test-macro) (args)))) ;you almost never need eval.
(defn calls-calls-test-macro [& args]
(calls-test-macro args))
This is actually a really good example of one of the ways macros are hard to compose. (some would say they cant be composed cleanly, though i think thats an exageration)
Macros are not magic. They are a mechanism to convert code at compile-time to equivalent code; they are not used at run-time. The pain you are feeling is because you are trying to do something you should not be trying to do.
I don't know the library in question, but if cass/set-attr! is a function, I see no reason why the macro you defined has to be a macro; it could be a function instead. You can do what you want to do if you can rewrite your macro as a function instead.
Your requirements aren't clear. I don't see why a macro is necessary here for test-macro, unless you're trying to print the unevaluated forms supplied to your macro.
These functions provide your expected results, but that's because your sample data was self-evaluating.
(defn test-args
[& args]
(println (format "count=%d; args=%s"
(count args)
(apply str args))))
or
(defn test-args
[& args]
(print (format "count=%d; args=" (count args)))
(doseq [a args]
(pr a))
(newline))
You can imagine other variations to get to the same result.
Try calling that function with something that doesn't evaluate to itself, and note the result:
(test-args (+ 1 2) (+ 3 4))
Were you looking to see the arguments printed as "37" or "(+ 1 2)(+ 3 4)"?
If you were instead trying to learn about macros and their expansion in general, as opposed to solving this particular problem, please tune your question to probe further.
pprint's docs are kind of a brick wall. If you pprint a map, it comes out on one line like so: {:a "b", :b "c", :d "e"}. Instead, I'd like to be pprinted like this, optionally with commas:
{:a "b"
:b "c"
:d "e"}
How would one do that with pprint?
You can set the *print-right-margin* binding:
Clojure=> (binding [*print-right-margin* 7] (pprint {:a 1 :b 2 :c 3}))
{:a 1,
:b 2,
:c 3}
Not exactly what you're looking for, but it might be enough?
BTW, the best way to figure this out —or at least the approach I took— is to use
Clojure=> (use 'clojure.contrib.repl-utils)
Clojure=> (source pprint)
(defn pprint
"Pretty print object to the optional output writer. If the writer is not provided,
print the object to the currently bound value of *out*."
([object] (pprint object *out*))
([object writer]
(with-pretty-writer writer
(binding [*print-pretty* true]
(write-out object))
(if (not (= 0 (.getColumn #^PrettyWriter *out*)))
(.write *out* (int \newline))))))
nil
Hmmrmmm.. what does with-pretty-writer do to *out*?
Clojure=> (source clojure.contrib.pprint/with-pretty-writer)
(defmacro #^{:private true} with-pretty-writer [base-writer & body]
`(let [new-writer# (not (pretty-writer? ~base-writer))]
(binding [*out* (if new-writer#
(make-pretty-writer ~base-writer *print-right-margin* *print-miser-width*)
~base-writer)]
~#body
(if new-writer# (.flush *out*)))))
nil
Okay, so *print-right-margin* sounds promising...
Clojure=> (source clojure.contrib.pprint/make-pretty-writer)
(defn- make-pretty-writer
"Wrap base-writer in a PrettyWriter with the specified right-margin and miser-width"
[base-writer right-margin miser-width]
(PrettyWriter. base-writer right-margin miser-width))
nil
Also, this is pretty informative:
Clojure=> (doc *print-right-margin*)
-------------------------
clojure.contrib.pprint/*print-right-margin*
nil
Pretty printing will try to avoid anything going beyond this column.
Set it to nil to have pprint let the line be arbitrarily long. This will ignore all
non-mandatory newlines.
nil
Anyway —and perhaps you already knew even this— if you really want to customize the way that pprint works, you can proxy clojure.contrib.pprint.PrettyWriter and pass that down by binding it to *out*. The PrettyWriter class is pretty large and intimidating, so I'm not sure if this was what you originally meant by your "brick wall" comment.
I don't think you can do that, you'll probably need to write your own, something like:
(defn pprint-map [m]
(print "{")
(doall (for [[k v] m] (println k v)))
(print "}"))