How to print a list as a string without parentheses - clojure

I did:
user=> (println (for [line (range 1 5)] (str "line=" line)))
and got:
(line=1 line=2 line=3 line=4)
but I wanted only line=1 line=2 line=3 line=4 as a string. How do I do this?

You need 'apply'.
(apply println (for [line (range 1 5)] (str "line=" line)))
Alternatively,
(println (apply str (interpose " " (map #(str "line=" %) (range 1 5)))))

What about this one. doseq is about doing side-effect on sequences and printing is a side-effect.
(doseq [line (range 1 5)
:let [msg (str "line=" line " ")]]
(print msg))

Instead of apply, you could alternatively use reduce like so:
user> (reduce #(str %1 " line=" %2) "" (range 1 5))
=> " line=1 line=2 line=3 line=4"
The reduce function is a function that takes a function (let's call if f), a "starting value", and then a list of things that will be used as the second argument to f. It lazily calls f on the starting value and the first item in the list, then calls f on what this returns and the second item in the list, then calls f on what this returns and the third item in the list etc., until it has exhausted all the items in the list (or rather--since it's lazy, it will only go through the whole list if you "ask it to").
If you don't like starting space, you could wrap the whole thing in triml (you'd have to do (use 'clojure.string) first). Or you could do (reduce #(str %1 "line=" %2 " ") (range 1 5)), which would put the space at the end.
My experience has been that anytime you can do something with apply, you can do it slightly more elegantly with reduce. More importantly, my reduce alternative has always usually been faster than my apply one. I certainly can't vouch that this will be true always, and I haven't done speed tests for your particular problem.
Edit
I did some rough timings, using my version (reduce) versus JohnJ's second suggestion (apply), and found that they were pretty similar for up to (range 1 100), but that by (range 1 500), the apply version was at least 4x faster.

Related

Compact way in Clojure to print a variable number of command line arguments?

I'm a newbie to Clojure. I think I'm trying to solve this procedurally and there must be a better (more functional) way to do this in Clojure...
The -main function can receive a variable number of 'args'. I would like to print them out but avoid an IndexOutOfBoundsException. I thought I could mimic Java and use a case fall-through to minimize the code involved, but that didn't work:
(defn -main [& args]
(println "There are" (str (count args)) "input arguments.")
(println "Here are args:" (str args))
(let [x (count args)]
(case x
(> x 0) (do
(print "Here is the first arg: ")
(println (nth args 0)))
(> x 1) (do
(print "Here is the 2nd arg: ")
(println (nth args 1)))
(> x 2) (do
(print "Here is the 3rd arg: ")
(println (nth args 2))))))
(doseq [[n arg] (map-indexed vector arguments)]
(println (str "Here is the argument #" (inc n) ": " (pr-str arg))))
map-indexes is like map but adds index number in the beginning.
So it goes item by item through arguments, packs index and item into a vector and by destructruing index number and item are mapped to [n arg].
Since clojure begins counting from 0, you use (inc n) to begin counting from 1. pr-str is pretty print string. The str joins all string components together.
there is also a handy formatting facility in clojure's core library: cl-format, which is the port of common lisp's format syntax. It includes a nice way to print out collections:
(require '[clojure.pprint :refer [cl-format]])
(let [args [:a :b :c :d]]
(cl-format true "~{here is the ~:r arg: ~a~%~}"
(interleave (rest (range)) args)))
;; here is the first arg: :a
;; here is the second arg: :b
;; here is the third arg: :c
;; here is the fourth arg: :d
some more information about what format can do is here

How to really shuffle sequence in Clojure?

(defn shuffle-letters
[word]
(let [letters (clojure.string/split word #"")
shuffled-letters (shuffle letters)]
(clojure.string/join "" shuffled-letters)))
But if you put in "test" you can get "test" back sometimes.
How to modify the code to be sure that output will never be equal to input.
I feel embarrassing, I can solve it easily in Python, but Clojure is so different to me...
Thank you.
P.S. I thing we can close the topic now... The loop is in fact all I needed...
You can use loop. When the shuffled letters are the same as the original, recur back up to the start of the loop:
(defn shuffle-letters [word]
(let [letters (clojure.string/split word #"")]
(loop [] ; Start a loop
(let [shuffled-letters (shuffle letters)]
(if (= shuffled-letters letters) ; Check if they're equal
(recur) ; If they're equal, loop and try again
(clojure.string/join "" shuffled-letters)))))) ; Else, return the joined letters
There's many ways this could be written, but this is I think as plain as it gets. You could also get rid of the loop and make shuffle-letters itself recursive. This would lead to unnecessary work though. You could also use let-fn to create a local recursive function, but at that point, loop would likely be cleaner.
Things to note though:
Obviously, if you try to shuffle something like "H" or "HH", it will get stuck and loop forever since no amount of shuffling will cause them to differ. You could do a check ahead of time, or add a parameter to loop that limits how many times it tries.
This will actually make your shuffle less random. If you disallow it from returning the original string, you're reducing the amount of possible outputs.
The call to split is unnecessary. You can just call vec on the string:
(defn shuffle-letters [word]
(let [letters (vec word)]
(loop []
(let [shuffled-letters (shuffle letters)]
(if (= shuffled-letters letters)
(recur)
(clojure.string/join "" shuffled-letters))))))
Here's another solution (using transducers):
(defn shuffle-strict [s]
(let [letters (seq s)
xform (comp (map clojure.string/join)
(filter (fn[v] (not= v s))))]
(when (> (count (into #{} letters)) 1)
(first (eduction xform (iterate shuffle letters))))))
(for [_ (range 20)]
(shuffle-strict "test"))
;; => ("etts" "etts" "stte" "etts" "sett" "tste" "tste" "sett" "ttse" "sett" "ttse" "tset" "stte" "ttes" "ttes" "stte" "stte" "etts" "estt" "stet")
(shuffle-strict "t")
;; => nil
(shuffle-strict "ttttt")
;; => nil
We basically create a lazy list of possible shuffles, and then we take the first of them to be different from the input. We also make sure that there are at least 2 different characters in the input, so as not to hang (we return nil here since you don't want to have the input string as a possible result).
If you want your function to return a sequence:
(defn my-shuffle [input]
(when (-> input set count (> 1))
(->> input
(iterate #(apply str (shuffle (seq %))))
(remove #(= input %)))))
(->> "abc" my-shuffle (take 5))
;; => ("acb" "cba" "bca" "acb" "cab")
(->> "bbb" my-shuffle (take 5))
;; => ()

How to define a repeat function with macros

I want to write a function (rep-n-times n & args), which should work like:
user=>(rep-n-times 3 (print "hello!") (print "bye"))
hello! bye hello! bye hello! bye nil
My code is
(defmacro ntimes [n & body]
`(take ~n (repeat ~#body)))
Testing:
#'user/rep-n-times
user=> (rep-n-ntimes 5 (print "hah"))
hah(nil nil nil nil nil)
user=> (macroexpand '(rep-n-ntimes 4 (print "hello")))
(clojure.core/take 4 (clojure.core/repeat (print "hello")))
How can I fix it?
In this case where you are doing things for side effects, you should use doseq or dotimes instead:
(dotimes [i 3]
(print "hello! bye "))
There is no need to define rep-n-times. If you need the results of a function with side-effects, use repeatedly. Note also that repeatedly and repeat optionally takes the number of repetitions as an argument.
(repeatedly 3 (fn [] (print "hello! bye ") (rand-int 10)))
However as to the problem with your definition of rep-n-times, calling repeat takes a single argument, which is the evaluated result of (print "hello") which is nil. So you are asking for 4 nils, and getting 4 nils. The print occurs one time, when the argument is evaluated to nil. Also it produces a lazy sequence, which happens to be evaluated at the REPL, but that is just because it is being printed. You should avoid having side effects (such as printing) inside a lazy sequence, because they will not be evaluated unless you explicitly realize the sequence.
Note that dotimes can take many forms:
(dotimes [i 3] (print "h1") (print "h2") (print "h3"))
And that dotimes is a macro defined here
You can write your own version by using that code as a starting point:
(defmacro rep-n-times [n & body]
`(loop [i# ~n]
(when (pos? i#)
~#body
(recur (dec i#)))))

clojure using map to count the elements a vector of list

As you can see my first element is somehow being skipped... at least println thinks it is.
(def example [(:1 :1 :1) (:2 :2 :2 :2) (:3 :3)])
(println example)
(defn countEachSequence [vec]
(println vec)
(let [varName (count vec)]
(println varName)
)
)
(map #(countEachSequence %) example)
Desired output is:
([1 3] [:2 4] [:3 2])
This is naming the group and count the amount of elements in that group.
This seems what you want:
(defn count-each-seq [v]
(map (fn [s] [(first s) (count s)]) v))
The above count-each-seq function returns a sequence of vector. You can print it later.
If you run the function in REPL, the result will displayed immediately.
There are three things to say in your code:
When you write code, you should separate the core logic and presentation (in this case, println). And your function should return a value.
Your parameter vec is actually a function name clojure.core/vec. Pick other name that doesn't conflict with the existing function name.
Using dash between word is the clojure (or LISP) convention. So name like count-each-sequence instead of camel case.

Given a clojure vector, iteratively remove 1 element

I'm trying to build a set of functions to compare sentences to one another. So I wrote a function called split-to-sentences that takes an input like this:
"This is a sentence. And so is this. And this one too."
and returns:
["This is a sentence" "And so is this" "And this one too."]
What I am struggling with is how to iterate over this vector and get the items that aren't the current value. I tried nosing around with drop and remove but haven't quite figured it out.
I guess one thing I could do is use first and rest in the loop and conj the previous value to the output of rest.
(remove #{current-value} sentences-vector)
Just use filter:
(filter #(not= current-value %) sentences-vector)
I believe you may want something like this function:
(defn without-each [x]
(map (fn [i] (concat (subvec x 0 i) (subvec x (inc i))))
(range (count x))))
Use it like this:
>>> (def x ["foo" "bar" "baz"])
>>> (without-each x)
==> (("bar" "baz") ("foo" "baz") ("foo" "bar"))
The returned elements are lazily concatenated, which is why they are not vectors. This is desirable, since true vector concatenation (e.g. (into a b)) is O(n).
Because subvec uses sharing with the original sequence this should not use an excessive amount of memory.
The trick is to pass your sentences twice into the reduce function...
(def sentences ["abcd" "efg" "hijk" "lmnop" "qrs" "tuv" "wx" "y&z"])
(reduce
(fn [[prev [curr & foll]] _]
(let [aren't-current-value (concat prev foll)]
(println aren't-current-value) ;use it here
[(conj prev curr) foll]))
[[] sentences]
sentences)
...once to see the following ones, and once to iterate.
You might consider using subvec or pop because both operate very quickly on vectors.