I have a vector that looks like:
[ "1" "2" "3" "4" ]
I wish to write a function returns the vector to:
[ 1 "2" 3 4 ]
; Note that the second element is still a string
Note that nothing is changed, an entirely new vector is returned. What is the simplest way to do this in clojure?
map-indexed is a decent choice. call a function you pass with the value of one of the items form your input and the index where it was found (index first). that function can choose to produce a new value or return the existing one.
user> (map-indexed (fn [i v]
(if-not (= 1 i)
(Integer/parseInt v)
v))
[ "1" "2" "3" "4"])
(1 "2" 3 4)
When the if returns v it is the exact same value in the resulting map so you keep the benefits of structural sharing in the parts you choose to keep. If you want the output to be kept as a vector then you can use mapv and pass the index sequence your self.
user> (mapv (fn [i v]
(if-not (= 1 i)
(Integer/parseInt v)
v))
(range)
[ "1" "2" "3" "4"])
[1 "2" 3 4]
there are many ways to write this
Here is how I would do it. Note that the index is zero-based:
(defn map-not-nth
"Transform all elements of coll except the one corresponding to idx (zero-based)."
[func coll idx]
{:pre [ (<= 0 idx (count coll)) ]
:post [ (= (count %) (count coll))
(= (nth coll idx) (nth % idx) ) ] }
(let [coll-tx (map func coll) ; transform all data
result (flatten [ (take idx coll-tx) ; [0..idx-1]
(nth coll idx) ; idx
(drop (inc idx) coll-tx) ; [idx+1..N-1]
] ) ]
result ))
(def xx [ 0 1 2 3 4 ] )
(prn (map-not-nth str xx 0))
(prn (map-not-nth str xx 1))
(prn (map-not-nth str xx 2))
(prn (map-not-nth str xx 3))
(prn (map-not-nth str xx 4))
Result is:
user=> (prn (map-not-nth str xx 0))
(0 "1" "2" "3" "4")
user=> (prn (map-not-nth str xx 1))
("0" 1 "2" "3" "4")
user=> (prn (map-not-nth str xx 2))
("0" "1" 2 "3" "4")
user=> (prn (map-not-nth str xx 3))
("0" "1" "2" 3 "4")
user=> (prn (map-not-nth str xx 4))
("0" "1" "2" "3" 4)
Related
I created a polynomial function that returns the string based representation of the terms of polynomial added together, however i was having difficulties in removing terms from the string that contain the 0 coefficient and its giving me a different output
Below is my function:
(defn format-poly [poly]
(clojure.string/join ""
(map-indexed (fn [index item] (cond
(= index 0) item
(= (get item 0) \-) item
:default (str "+" item)))
(reverse (for [[pow coeff] (map-indexed vector (rseq (:coefficients poly))) ; remove whatever is causing a negative coeff to be ignored
]
(cond
(= coeff 0) (remove zero? [pow coeff])
(= coeff 1) (format "%s^%d",(:variable poly) pow)
(= pow 0) (format "%s",coeff)
:else
(format "%d%s^%d" coeff (:variable poly) pow)))))))
sample input:
(format-poly {:variable "x"
:coefficients [1 0 0 2 3 4]})
Expected output:
"x^6-2x^5+3x^4-4x^3+5x^2-6x^1+7"
i would propose gathering all the polynom print parts altogether into a flat collection, and then print all of them to string. Could look like this:
(defn format-poly [v coeffs]
(let [fmt-parts (mapcat (fn [coeff pow]
(when-not (zero? coeff)
[(if (neg? coeff) "-" "+")
(let [coeff (Math/abs coeff)]
(if (== 1 coeff) "" coeff))
(cond (zero? pow) ""
(== 1 pow) v
:else (str v "^" pow))]))
coeffs
(range (dec (count coeffs)) -1 -1))]
(apply str (if (= "+" (first fmt-parts))
(rest fmt-parts)
fmt-parts))))
user> (format-poly "x" [-1 -2 3 0 4 5])
;; "-x^5-2x^4+3x^3+4x+5"
user> (format-poly "x" [1 -2 3 0 4 5])
;; "x^5-2x^4+3x^3+4x+5"
user> (format-poly "x" [1 2 3 0 4 5])
;; "x^5+2x^4+3x^3+4x+5"
I was trying to modify a vector of vector but ended up with lazy-seq inside. I am new to clojure. Can someone help me to get this correctly?
(require '[clojure.string :as str])
;;READ CUST.TXT
(def my_str(slurp "cust.txt"))
(defn esplit [x] (str/split x #"\|" ))
(def cust (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i cust] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH CUST
(defn cust_find [x] (for [i cust :when (= (first i) x )] (do (nth i 1))))
(type (cust_find "2"))
;;READ PROD.TXT
(def my_str(slurp "prod.txt"))
(def prod (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i prod] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH PROD
(defn prod_find [x y] (for [i prod :when (= (first i) x )] (nth i y)))
(prod_find "2" 1)
(def my_str(slurp "sales.txt"))
(def sales (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
; (for [i (range(count sales))] (cust_find (nth (nth sales i) 1)))
; (defn fill_sales_1 [x]
; (assoc x 1
; (cust_find (nth x 1))))
; (def sales(map fill_sales_1 (sales)))
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (str (cust_find (nth (nth sales i) 1)))))))
; (for [i (range(count sales))] (assoc (nth sales i) 2 (str (prod_find (nth (nth sales i) 2) 1))))
(for [i sales] (println i))
When I print sales vector I get
[1 clojure.lang.LazySeq#10ae5ccd 1 3]
[2 clojure.lang.LazySeq#a5d0ddf9 2 3]
[3 clojure.lang.LazySeq#a5d0ddf9 1 1]
[4 clojure.lang.LazySeq#d80cb028 3 4]
If you need the text files I will upload them as well.
In Clojure, for and map, as well as other functions and macros working with sequences, generate a lazy sequence instead of a vector.
In the REPL, lazy sequences are usually fully computed when printing - to have it printed, it's enough to remove the str in your second to last line:
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (cust_find (nth (nth sales i) 1))))))
Just in case, note that your code can be prettified / simplified to convey the meaning better. For example, you are just iterating over a sequence of sales - you don't need to iterate over the indices and then get each item using nth:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (nth rec 1)))))
Second, you can replace nth ... 1 with second - it will be easier to understand:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (second rec))))
Or, alternatively, you can just use update instead of assoc:
(def sales
(vec (for [rec sales])
(update rec 1 cust_find)))
And, do you really need the outer vec here? You can do most of what you intend without it:
(def sales
(for [rec sales])
(update rec 1 cust_find))
Also, using underscores in Clojure function names is considered bad style: dashes (as in cust-find instead of cust_find) are easier to read and easier to type.
(for [i sales] (println (doall i)))
doall realizes a lazy sequence. Bare in mind that if the sequence is huge, you might not want to do this.
I'm looking for a function with the following behavior
(split-on "" ("" "test" "one" "" "two"))
(() ("test" "one") ("two"))
I can't find it in 'core', and I'm not sure how to look it up. Suggestions?
Edit:
split-when looks promising, but I think I am using it wrong.
(t/split-when #(= "" %) '("" "test" "one" "" "two"))
[["" "test" "one" "" "two"] ()]
whereas I am looking for the return value of
[[] ["test" "one"] ["two"]]
partition-by is close. You can partition the sequence by members that are equal fo the split token:
(partition-by #(= "" %) '("" "test" "one" "" "two"))
(("") ("test" "one") ("") ("two"))
This leaves extra seperators in there, though that's easy enough to remove:
(remove #(= '("") %)
(partition-by empty? ["" "test" "one" "" "two"]))
(("test" "one") ("two"))
If you want to get fancy about it and make a transducer out of that, you can define one like so:
(def split-on
(comp
(partition-by #(= "" %))
(remove #(= '("") %))))
(into [] split-on ["" "test" "one" "" "two"])
[["test" "one"] ["two"]]
This does it on "one pass" without building intermediate structures.
To make that into a normal function (if you don't want a transducer):
(defn split-on [coll]
(into [] (comp
(partition-by #(= "" %))
(remove #(= '("") %)))
coll))
I was looking for exactly this function recently and had to create it myself. It is available in the Tupelo library. You can see the API docs here: http://cloojure.github.io/doc/tupelo/tupelo.core.html#var-split-when
(split-when pred coll)
Splits a collection based on a predicate with a collection
argument. Finds the first index N such that (pred (drop N coll))
is true. Returns a length-2 vector of [ (take N coll) (drop N coll) ].
If pred is never satisified, [ coll [] ] is returned.
The unit tests show the function in action (admittedly boring test data):
(deftest t-split-when
(is= [ [] [0 1 2 3 4] ] (split-when #(= 0 (first %)) (range 5)))
(is= [ [0] [1 2 3 4] ] (split-when #(= 1 (first %)) (range 5)))
(is= [ [0 1] [2 3 4] ] (split-when #(= 2 (first %)) (range 5)))
(is= [ [0 1 2] [3 4] ] (split-when #(= 3 (first %)) (range 5)))
(is= [ [0 1 2 3] [4] ] (split-when #(= 4 (first %)) (range 5)))
(is= [ [0 1 2 3 4] [] ] (split-when #(= 5 (first %)) (range 5)))
(is= [ [0 1 2 3 4] [] ] (split-when #(= 9 (first %)) (range 5)))
You can also read the source if you are interested.
I'd like to generate binary numbers of n digits from 0 to 2^n-1. For example of 3 digits, "000", "001", "010", ..., "111" (0 to 7 in decimal). The way I used is to use java.lang.Integer.toBinaryString() method and add zeros if necessary like the following:
(defn pad-zero [s n]
(str (reduce str (repeat (- n (count s)) "0")) s))
(defn binary-permutation [n]
(map (fn [s] (pad-zero s n))
(map #(Integer/toBinaryString %) (range 0 (Math/pow 2 n)))))
With this code, I can generate what I want like this. For 3 digits:
(binary-permutation 3)
=> ("000" "001" "010" "011" "100" "101" "110" "111")
But this codes look a little verbose.
Aren't there any ways better or more clojure way to do this?
You can simplify the formatting using cl-format from clojure.pprint:
(defn binary-permutation [n]
(map (partial cl-format nil "~v,'0B" n) (range 0 (Math/pow 2 n))))
You may also be interested to know that (Math/pow 2 n) is equivalent to (bit-shift-left 1 n).
Another way to express this would be in term of selections from clojure.math.combinatorics:
(defn binary-permutation [n]
(map (partial apply str) (selections [0 1] n)))
(defn binary-permutation [n]
(for [x (range (Math/pow 2 n))]
(apply str (reverse (take n (map #(bit-and 1 %) (iterate #(bit-shift-right % 1) x)))))))
(defn pad-zero [s n]
(apply str (take-last n (concat (repeat n \0) s))))
I need to define a function which takes a sequence and some functions which act on elements inside the sequence. It returns a sequence from the old sequence where the elements with duplicate function values are removed.
(defn dedup [seq & functions] ...)
for example, if
(f1 1) = 'a'
(f1 2) = 'a'
(f1 3) = 'c'
(f1 4) = 'd'
(f2 1) = 'za'
(f2 2) = 'zb'
(f2 3) = 'zc'
(f2 4) = 'zb'
then
(dedup [1 2 3 4] f1 f2)
returns a sequence of (1 3)
how do I do it?
EDIT:
edited the test values so as not to create misunderstanding
EDIT:
Below is the (not so functional) implementation for the case of only 1 function
(defn dedup [seq f]
(loop [values #{} seq1 seq seq2 '()]
(let [s (first seq1)]
(if (nil? s)
(reverse seq2)
(let [v (f s)]
(if (contains? values v)
(recur values (rest seq1) seq2)
(recur (conj values v) (rest seq1) (conj seq2 s))))))))
your example seems to contradict the text - it is returning values where the two functions agree.
(defn dedup [seq & fns]
(for [s seq :when (apply = (map #(% s) fns))] s))
(dedup [1 2 3 4]
#(case % 1 "a" 2 "a" 3 "c" 4 "d")
#(case % 1 "a" 2 "b" 3 "c" 4 "b"))
(1 3)
maybe that's a little too compact? #(... % ...) is equivalent to (fn [x] (... x ...)) and the map in dup runs over the functions, applying them all to the same value in the sequence.
you could also test with
(dedup [1 2 3 4] {1 "a" 2 "a" 3 "c" 4 "d"} {1 "a" 2 "b" 3 "c" 4 "b"})
(1 3)
ps i think maybe the confusion is over english meaning. "duplicate" means that a value repeats. so "a" "a" is a duplicate of "a". i suspect what you meant is "multiple" - you want to remove entries where you get multiple (distinct) values.
pps you could also use filter:
(defn dedup [seq & fns]
(filter #(apply = (map (fn [f] (f %)) fns)) seq))
where i needed to write one anonymous function explicitly because you can't nest #(...).