I have a toy project where I would like to add some string values into a Redis db. The input is coming from a huge CSV file. The (lazy) function below works fine , but I do not know how to add to the key the indexed value read into the input file - the two commented lines.
Could you give me hint/URL/reference for it? Thank you!
(defn collector [myfile]
(with-open [rdr (io/reader myfile)]
(doseq [line (line-seq rdr)]
; [idx (iterate inc 0)]
(let [[k v1 v2 v3 v4 v5 v6 v7] (clojure.string/split line #",")]
(red/set db
(str "key:" k)
;(str "key:" k ":" idx)
(str v1 "-" v5 "-" v6))))))
the best thing you can do without changing your code structure, is to attach the index to the lines seq this way:
(doseq [[idx line] (map-indexed vector (line-seq rdr))] ...)
then the second commented line would work as planned.
(map-indexed vector coll) would pass the two parameters (index and the element of the sequence) to the vector function, making the tuple of them, and destructuring bind [idx line] binds its elements to desired names.
This is a commonly used idiom to index the collection. Also you could do it this way:
(map vector (range) coll), which works the same way as map-indexed, though this idiom is usable to make tuples of any collections:
(map vector (range) [:a :b :c :d] (iterate (partial * 2) 1))
;;=> ([0 :a 1] [1 :b 2] [2 :c 4] [3 :d 8])
Related
I am fairly new to Clojure and would help help with some code. I have a function which takes a vector and i would like to loop through the vector and get the value at an index 'i' and the value of 'i' itself. 'i' is the value which is incremented in the loop.
I have checked 'for' at the clojure docs at for and wrote the following code.
(for [i some-vector]
(print (get-intersec i (.length some-vector) loop-count)))
The loop-count variable is supposed to be the loop count.
I have also checked loop but it does not seem like a feasible solution. Can someone help me with a clojure function i can use or help me write a macro or function that can do that.
Thank you.
Ps: To solve my problem, i use my own counter but would like a better solution.
First, keep in mind that for is for list comprehension, that is, creating new sequences. For looping through a sequence for some side effect, like printing, you probably want to use doseq.
To include a numeric count with each element as you loop through, you can use map-indexed:
(def xs [:a :b :c :d])
(doseq [[n elem] (map-indexed #(vector %1 %2) xs)]
(println n "->" elem))
Output:
0 -> :a
1 -> :b
2 -> :c
3 -> :d
If you find yourself doing this a lot, like I did, you can create a macro:
(defmacro doseq-indexed [[[item idx] coll] & forms]
`(doseq [[~idx ~item] (map-indexed #(vector %1 %2) ~coll)]
~#forms))
And use it like this:
> (doseq-indexed [[n elem] xs] (println n "->" elem))
0 -> :a
1 -> :b
2 -> :c
3 -> :d
Don't forget dotimes for simple stuff like this:
(let [data [:a :b :c :d]]
(dotimes [i (count data)]
(println i " -> " (data i))
; or (nth data i)
; or (get data i)
))
with result
0 -> :a
1 -> :b
2 -> :c
3 -> :d
Using loop/recur would look like this:
(let [data [:a :b :c :d]]
(loop [i 0
items data]
(let [curr (first items)]
(when curr
(println i "->" curr)
(recur (inc i) (rest items))))))
Update:
If you need this a lot, I already wrote a function that will add the index value to the beginning of each entry in a sequence:
(ns tst.demo.core
(:use tupelo.test)
(:require [tupelo.core :as t]) )
(dotest
(let [data [:a :b :c :d]]
(t/spy-pretty :indexed-data
(t/indexed data))))
with result
:indexed-data =>
([0 :a]
[1 :b]
[2 :c]
[3 :d])
The general signature is:
(indexed & colls)
Given one or more collections, returns a sequence of indexed tuples
from the collections like:
(indexed xs ys zs) -> [ [0 x0 y0 z0]
[1 x1 y1 z1]
[2 x2 y2 z2]
... ]
If your not set on using for, you could use map-indexed e.g.
(map-indexed (fn [i v]
(get-intersect v (.length some-vector) i))
some-vector))
I don't know what get-intersect is and assume .length is java interop? Anyway, map-indexed expects a function of 2 arguments, the 1st is the index and the second is the value.
Is there a convenient way in ClojureScript to pretty print a nested hash-map in the way that the whole tree-structure becomes immediately visible.
For instance a map like this
(def my-map {:a {:b 1 :c 9} :b {:d 8 :e {:f 2 :g 3 :h 4}} :c 10})
should be printed like this:
{:a {:b 1
:c 9}
:b {:d 8
:e {:f 2
:g 3
:h 4}}
:c 10}
EDIT: There might also be vectors in the map. The usecase is just to inspect larger data structures during development.
There is no built-in way to do it. You might come close to what you want by using cljs.pprint and setting cljs.pprint/*print-right-margin* to a low value.
I would recommend to take a look at a small library shodan which provides a very useful inspect function:
(require '[shodan.inspection :refer [inspect]])
(inspect {:aaaaaa 1
:bbbbbb {:ccc 2
:dddddd [1 2 3 4 5]}})
It won't print anything in your CLJS REPL but will provide a handy view in your browser's console:
You can collapse and expand nested datastructures - it basically does what you asked for.
As a personal challenge I wrote the following code:
(enable-console-print!)
(def atomic? (complement coll?))
(def padding #(apply str (repeat % " ")))
(def tabulate #(apply str (repeat % "\t")))
(def strcat #(->> (apply concat %&) (apply str)))
(defn my-max-key [x] (if (empty? x) [""] (apply (partial max-key count) x)))
(defn longest-key [m] (->> m keys (filter atomic?) (map str) my-max-key))
(def length (comp count str))
(def not-map? (complement map?))
(def nested? #(some coll? %))
(def join #(apply str (interpose % %2)))
(def join-lines (partial join "\n"))
(defn has-atomic? [coll] (some atomic? coll))
(defn diff-key-lengths [key1 key2] (- (length key1) (length key2)))
(defn convert
([thing] (convert -1 thing))
([depth thing]
(defn convert-items []
(defn convert-seq []
(conj []
(map (partial convert (inc depth)) thing)
""))
(defn string-horizontally [[key value]]
(str (tabulate (inc depth))
key
(padding (diff-key-lengths (longest-key thing) key))
" → "
value))
(defn string-vertically [[key value]]
(str (convert (inc depth) key) "\n"
(convert (+ 2 depth) "↓") "\n"
(convert (inc depth) value) "\n"))
(defn convert-kv [[key value]]
(if (nested? [key value])
(string-vertically [key value])
(string-horizontally [key value])))
(cond (atomic? thing)
[(str (tabulate depth) thing)]
(not-map? thing)
(convert-seq)
(map? thing)
(map convert-kv thing)))
(->> (convert-items) flatten join-lines)))
(def sample-input [["the first thing in this nested vector"]
{{"this is a key in a nested map"
"that points to me!!!"}
{"and that entire map points to this map!!!"
"cool!!!"
"but it gets cooler cause..."
"the value's line up!!!"}}])
(->> sample-input convert println)
The terminal output is (psst... the values in a map do line up but I don't think that chrome uses a monospaced font!):
I have the following variable
(def a [[1 2] [3 4] [5 6]])
and want to return
[[1 3 5][2 4 6]]
and if input is
[[1 2] [3 4] [5 6] [7 8 9]] then the required result is
[[1 3 5 7] [2 4 6 8] [9]]
How to do it in clojure?
(persistent!
(reduce
(fn [acc e]
(reduce-kv
(fn [acc2 i2 e2]
(assoc! acc2 i2 ((fnil conj []) (get acc2 i2) e2)))
acc
e))
(transient [])
[[1 2 3] [:a :b] [\a] [111] [200 300 400 500]]))
;;=> [[1 :a \a 111 200] [2 :b 300] [3 400] [500]]
An empty vector can be updated via the update-in fn at the 0th index, a non-empty vector can be, additionally, updated at the index immediately following the last value.
The reduction here is about passing the outer accumulator to the inner reducing function, updating it accordingly, and then returning it back to the outer reducing function, which in turn will pass again to the inner rf for processing the next element.
EDIT: Updated to fastest version.
I like ifett's implementation, though it seems weird to use reduce-kv to build a vector that could be easily build with map/mapv.
So, here is how I would've done it:
(defn transpose [v]
(mapv (fn [ind]
(mapv #(get % ind)
(filter #(contains? % ind) v)))
(->> (map count v)
(apply max)
range)))
(->> (range)
(map (fn [i]
(->> a
(filter #(contains? % i))
(map #(nth % i)))))
(take-while seq))
Notice that this algorithm creates a lazy seq of lazy seqs so you that you will only pay for the transformations you really consume. If you insist on creating vectors instead, wrap the forms in vec at the necessary places - or if you are using Clojurescript or don't mind a Clojure 1.7 alpha use transducers to create vectors eagerly without paying for laziness or immutability:
(into []
(comp
(map (fn [i]
(into [] (comp (filter #(contains? % i))
(map #(nth % i)))
a)))
(take-while seq))
(range))
I find this easy to understand:
(defn nth-column [matrix n]
(for [row matrix] (nth row n)))
(defn transpose [matrix]
(for [column (range (count (first matrix)))]
(nth-column matrix column)))
(transpose a)
=> ((1 3 5) (2 4 6))
nth-column is a list comprehension generating a sequence from the nth element of each sequence (of rows).
Then transpose-matrix is simply iterating over the columns creating a sequence element for each, consisting of (nth-column matrix column) i.e. the sequence of elements for that column.
(map
(partial filter identity) ;;remove nil in each sub-list
(take-while
#(some identity %) ;;stop on all nil sub-list
(for [i (range)]
(map #(get % i) a)))) ;; get returns nil on missing values
Use get to have nil on missing values, iterate (for) on an infinite range, stop on all nil sub-list, remove nil from sub-lists. Add vector constructor before first map and in it's function (first argument) if you really need vectors.
EDIT: please leave a comment if you think this is not useful. We can all learn from mistakes.
I need to build a seq of seqs (vec of vecs) by combining first, second, etc elements of the given seqs.
After a quick searching and looking at the cheat sheet. I haven't found one and finished with writing my own:
(defn zip
"From the sequence of sequences return a another sequence of sequenses
where first result sequense consist of first elements of input sequences
second element consist of second elements of input sequenses etc.
Example:
[[:a 0 \\a] [:b 1 \\b] [:c 2 \\c]] => ([:a :b :c] [0 1 2] [\\a \\b \\c])"
[coll]
(let [num-elems (count (first coll))
inits (for [_ (range num-elems)] [])]
(reduce (fn [cols elems] (map-indexed
(fn [idx coll] (conj coll (elems idx))) cols))
inits coll)))
I'm interested if there is a standard method for this?
(apply map vector [[:a 0 \a] [:b 1 \b] [:c 2 \c]])
;; ([:a :b :c] [0 1 2] [\a \b \c])
You can use the variable arity of map to accomplish this.
From the map docstring:
... Returns a lazy sequence consisting of the result of applying f to
the set of first items of each coll, followed by applying f to the set
of second items in each coll, until any one of the colls is exhausted.
Any remaining items in other colls are ignored....
Kyle's solution is a great one and I see no reason why not to use it, but if you want to write such a function from scratch you could write something like the following:
(defn zip
([ret s]
(let [a (map first s)]
(if (every? nil? a)
ret
(recur (conj ret a) (map rest s)))))
([s]
(reverse (zip nil s))))
I'm working my way through 4clojure and I'm stuck on Problem 156 (Map Defaults).
I can't figure out why the function bellow doesn't return a flat map
((fn [d k] (for [i k :let [r {}]]
(conj r [i d])))
[:a :b] [:foo :bar])
Current result is ({:foo [:a :b]} {:bar [:a :b]})
But I expected {:foo [:a :b], :bar [:a :b]}
Inside for, r is created anew in every iteration, gets populated with [i d] and gets yielded as an element of the lazy sequence. As a result, you obtain this sequence whose elements are small one-entry maps.
What you need is reduce. It loops over a sequence updating the accumulator using a function you provide:
(defn fun1 [d k]
(reduce
(fn [acc i] (conj acc [i d]))
{}
k))
It starts from an empty map, and for every element i in k it calls the lambda, which adds an entry to the map (passed to the lambda as acc). The result is one big map with all these entries.
Alternatively, you could just generate the key/value pairs with your for expression, and then use the into function to shove them all in a map:
((fn [d k] (into {} (for [i k] [i d])))
[:a :b] [:foo :bar])
; => {:foo [:a :b], :bar [:a :b]}
For those coming here looking for a flatmap function in Clojure, check out mapcat:
Returns the result of applying concat to the result of applying map to
f and colls.