I want to be able to loop through a collection but maintain a counter with that loop. I managed to create e.g.
(for [[email i] (map vector emails (range))]
...)
to do this, but ideally I'd prefer a fori macro (unless a function is possible but my gut says it's gotta be a macro) that lets me do equivalently
(fori [email i emails]
...)
or
(fori [[email i] emails]
...)
I've no experience with macros, and looking at the source for the for macro it looks pretty intimidating. Any help?
Super-cool would be a macro that follows the for syntax and allows e.g.
(fori [email i emails
line j (lines email)]
...)
You can write a macro that expands to for, but I'm not really convinced there's much point. There are numerous built-ins for exactly this purpose, and the fori syntax doesn't really read very well. At the very least it should look like
(fori [[email i] emails,
[line j] (lines email)]
...)
But if you really wanted to write it exactly as you said, it's certainly not impossible:
(defmacro fori [bindings body]
(letfn [(clauses [bindings]
(lazy-seq
(cond (empty? bindings) ()
(keyword? (first bindings)) (concat (take 2 bindings)
(clauses (drop 2 bindings)))
:else (let [[name index value] (take 3 bindings)]
(list* [index name] `(map-indexed vector ~value)
(clauses (drop 3 bindings)))))))]
`(for [~#(clauses bindings)]
~body)))
user> (macroexpand-1 '(fori [email i xs,
:when (even? i)
line j (lines email)]
[i line]))
(for [[i email] (map-indexed vector xs)
:when (even? i)
[j line] (map-indexed vector (lines email))]
[i line])
(defn fori [coll]
(map-indexed (fn [idx itm] [idx itm]) coll))
Is probably what you want. e.g.
(fori [:a :b :c :d])
produces
([0 :a] [1 :b] [2 :c] [3 :d])
BTW, for is not a loop but creates a list comprehension. If you're looking to do something with side effects inside a loop you should look into doseq.
Related
Hi am learning clojure and trying to find the index of the vowels in a string here is what I tried
(def vowels [\a \e \i \o \u \y])
(let [word-index (interleave "aaded" (range))
indexs (for [ [x i] (vector word-index)
:when (some #{x} vowels)]
[i] )]
(seq indexs))
But this is giving me index "0" or nill what am doing wrong.
> (def vowels #{\a \e \i \o \u})
> (filter some? (map #(when (vowels %1) %2) "aaded" (range)))
(0 1 3)
You need to form the input correctly for the for comprehension:
(let [word-index (interleave "aaded" (range))
indexs (for [[x i] (partition 2 word-index)
:when (some #{x} vowels)]
i)]
(prn (seq indexs)))
;; => (0 1 3)
interleave will give a lazy sequence when we mapped that sequence to the vector of for loop, I think I missed the indexes. So changed the implementation as below.
(let [word-index (zipmap (range) "aaded")
indexs (for [ [i x] word-index
:when (some #{x} vowels)]
[i] )
]
(flatten indexs)
)
Which is working fine, if anyone has better implementation please share. It will be helpful for me thanks.
With every iteration of the for function, the same hash-set is formed repeatedly. So it's better to define it in the let block. Also, we can use the hash-set directly as a function and we don't need the some function for the same.
(let [word-index (zipmap (range) "aaded")
vowels-hash (into #{} [\a \e \i \o \u \y])
indexs (for [[i x] word-index
:when (vowels-hash x)]
[i])]
(flatten indexs))
a bit different approach with regex:
for all indices:
user> (let [m (re-matcher #"[aeiou]" "banedif")]
(take-while identity (repeatedly #(when (re-find m) (.start m)))))
;;=> (1 3 5)
for single index:
user> (let [m (re-matcher #"[aeiou]" "bfsendf")]
(when (re-find m) (.start m)))
;;=> 3
user> (let [m (re-matcher #"[aeiou]" "bndf")]
(when (re-find m) (.start m)))
;;=> nil
#jas has got this nailed down already. Adding my own to provide some comments on what happens in intermediary steps.
Use sets to check for membership. Then the question "is this a vowel?" will be fast.
(def vowels (set "aeiouy"))
vowels
;; => #{\a \e \i \o \u \y}
We can filter out the vowels, then get just the indexes
(defn vowel-indices-1 [word]
(->> (map vector (range) word) ; ([0 \h] [1 \e] [2 \l] ...)
(filter (fn [[_ character]] ; ([1 \e] [4 \o])
(contains? vowels character)))
(map first))) ; (1 4)
(vowel-indices-1 "hello!")
;; => (1 4)
... or we can go for a slightly more fancy with the :when keyword (didn't know about that, thanks!), in the style that you started!
(defn vowel-indices-2 [word]
(for [[i ch] (map vector (range) word)
:when (contains? vowels ch)]
i))
(vowel-indices-2 "hello!")
;; => (1 4)
I'm often writing code of the form
(->> init
(map ...)
(filter ...)
(first))
When converting this into code that uses transducers I'll end up with something like
(transduce (comp (map ...) (filter ...)) (completing #(reduced %2)) nil init)
Writing (completing #(reduced %2)) instead of first doesn't sit well with me at all. It needlessly obscures a very straightforward task. Is there a more idiomatic way of performing this task?
I'd personally use your approach with a custom reducing function but here are some alternatives:
(let [[x] (into [] (comp (map inc) (filter even?) (take 1)) [0 1])]
x)
Using destructing :/
Or:
(first (eduction (map inc) (filter even?) [0 1])
Here you save on calling comp which is done for you. Though it's not super lazy. It'll realize up to 32 elements so it's potentially wasteful.
Fixed with a (take 1):
(first (eduction (map inc) (filter even?) (take 1) [0 1]))
Overall a bit shorter and not too unclear compared to:
(transduce (comp (map inc) (filter even?) (take 1)) (completing #(reduced %2)) nil [0 1])
If you need this a bunch, then I'd probably NOT create a custom reducer function but instead a function similar to transduce that takes xform, coll as the argument and returns the first value. It's clearer what it does and you can give it a nice docstring. If you want to save on calling comp you can also make it similar to eduction:
(defn single-xf
"Returns the first item of transducing the xforms over collection"
{:arglists '([xform* coll])}
[& xforms]
(transduce (apply comp (butlast xforms)) (completing #(reduced %2)) nil (last xforms)))
Example:
(single-xf (map inc) (filter even?) [0 1])
medley has find-first with a transducer arity and xforms has a reducing function called last. I think that the combination of the two is what you're after.
(ns foo.bar
(:require
[medley.core :as medley]
[net.cgrand.xforms.rfs :as rfs]))
(transduce (comp (map ,,,) (medley/find-first ,,,)) rfs/last init)
I am coming from a Java background trying to learn Clojure. As the best way of learning is by actually writing some code, I took a very simple example of finding even numbers in a vector. Below is the piece of code I wrote:
`
(defn even-vector-2 [input]
(def output [])
(loop [x input]
(if (not= (count x) 0)
(do
(if (= (mod (first x) 2) 0)
(do
(def output (conj output (first x)))))
(recur (rest x)))))
output)
`
This code works, but it is lame that I had to use a global symbol to make it work. The reason I had to use the global symbol is because I wanted to change the state of the symbol every time I find an even number in the vector. let doesn't allow me to change the value of the symbol. Is there a way this can be achieved without using global symbols / atoms.
The idiomatic solution is straightfoward:
(filter even? [1 2 3])
; -> (2)
For your educational purposes an implementation with loop/recur
(defn filter-even [v]
(loop [r []
[x & xs :as v] v]
(if (seq v) ;; if current v is not empty
(if (even? x)
(recur (conj r x) xs) ;; bind r to r with x, bind v to rest
(recur r xs)) ;; leave r as is
r))) ;; terminate by not calling recur, return r
The main problem with your code is you're polluting the namespace by using def. You should never really use def inside a function. If you absolutely need mutability, use an atom or similar object.
Now, for your question. If you want to do this the "hard way", just make output a part of the loop:
(defn even-vector-3 [input]
(loop [[n & rest-input] input ; Deconstruct the head from the tail
output []] ; Output is just looped with the input
(if n ; n will be nil if the list is empty
(recur rest-input
(if (= (mod n 2) 0)
(conj output n)
output)) ; Adding nothing since the number is odd
output)))
Rarely is explicit looping necessary though. This is a typical case for a fold: you want to accumulate a list that's a variable-length version of another list. This is a quick version:
(defn even-vector-4 [input]
(reduce ; Reducing the input into another list
(fn [acc n]
(if (= (rem n 2) 0)
(conj acc n)
acc))
[] ; This is the initial accumulator.
input))
Really though, you're just filtering a list. Just use the core's filter:
(filter #(= (rem % 2) 0) [1 2 3 4])
Note, filter is lazy.
Try
#(filterv even? %)
if you want to return a vector or
#(filter even? %)
if you want a lazy sequence.
If you want to combine this with more transformations, you might want to go for a transducer:
(filter even?)
If you wanted to write it using loop/recur, I'd do it like this:
(defn keep-even
"Accepts a vector of numbers, returning a vector of the even ones."
[input]
(loop [result []
unused input]
(if (empty? unused)
result
(let [curr-value (first unused)
next-result (if (is-even? curr-value)
(conj result curr-value)
result)
next-unused (rest unused) ]
(recur next-result next-unused)))))
This gets the same result as the built-in filter function.
Take a look at filter, even? and vec
check out http://cljs.info/cheatsheet/
(defn even-vector-2 [input](vec(filter even? input)))
If you want a lazy solution, filter is your friend.
Here is a non-lazy simple solution (loop/recur can be avoided if you apply always the same function without precise work) :
(defn keep-even-numbers
[coll]
(reduce
(fn [agg nb]
(if (zero? (rem nb 2)) (conj agg nb) agg))
[] coll))
If you like mutability for "fun", here is a solution with temporary mutable collection :
(defn mkeep-even-numbers
[coll]
(persistent!
(reduce
(fn [agg nb]
(if (zero? (rem nb 2)) (conj! agg nb) agg))
(transient []) coll)))
...which is slightly faster !
mod would be better than rem if you extend the odd/even definition to negative integers
You can also replace [] by the collection you want, here a vector !
In Clojure, you generally don't need to write a low-level loop with loop/recur. Here is a quick demo.
(ns tst.clj.core
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(defn is-even?
"Returns true if x is even, otherwise false."
[x]
(zero? (mod x 2)))
; quick sanity checks
(spyx (is-even? 2))
(spyx (is-even? 3))
(defn keep-even
"Accepts a vector of numbers, returning a vector of the even ones."
[input]
(into [] ; forces result into vector, eagerly
(filter is-even? input)))
; demonstrate on [0 1 2...9]
(spyx (keep-even (range 10)))
with result:
(is-even? 2) => true
(is-even? 3) => false
(keep-even (range 10)) => [0 2 4 6 8]
Your project.clj needs the following for spyx to work:
:dependencies [
[tupelo "0.9.11"]
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!):
Is there a way to mimic a this variable in something like (def foo {:two 2 :three (inc (:two this))})? Even better would be something like (def foo {:two 2 :three (inc ::two)}). I was told that there is a library that does exactly this, but I can't really find anything similar.
Thanks!
If you want a temporary name for something, that's what let is for.
(def foo (let [x {:two 2}]
(assoc x :three (inc (:two x)))))
I don't know of any library that does what you want. Every once in a while, someone suggests a "generalized arrow", like -> but with a magic symbol you can stick in the intermediary expressions which will be replaced by something else. See for example here and here. But this idea tends to be shot down because it's more complex and confusing for little benefit. let is your friend. See Rich's example:
(let [x []
x (conj x 1)
x (into x [2 3])
x (map inc x)]
...)
(Update: Rearranged & reworked. build-map and (a sketch of) -m> macros added.)
You could write this particular example as
(def foo (zipmap [:two :three] (iterate inc 2)))
The easiest general solution which occurs to me at this moment is
user> (-> {} (assoc :two 2) (#(assoc % :three (inc (:two %)))))
{:three 3, :two 2}
It's actually very flexible, although it does require you to write out assoc repeatedly.
To enable syntax similar to that from the question text, you could use something like this:
(defn build-map* [& kvs]
(reduce (fn [m [k v]]
(assoc m k (v m)))
{}
kvs))
(defmacro build-map [& raw-kvs]
(assert (even? (count raw-kvs)))
(let [kvs (map (fn [[k v]] [k `(fn [m#] (let [~'this m#] ~v))])
(partition 2 raw-kvs))]
`(build-map* ~#kvs)))
user> (build-map :two 2 :three (inc (:two this)))
{:three 3, :two 2}
You could easily change this to use a user-supplied symbol rather than the hardcoded this. Or you could switch to %, which is just a regular symbol outside anonymous function literals. Maybe add an explicit initial map argument, call it -m> (for map threading) and you can do
(-m> {} :two 2 :three (inc (:two %)))
for the same result.
Another funky way (mostly for the fun):
;;; from Alex Osborne's debug-repl,
;;; see http://gist.github.com/252421
;;; now changed to use &env
(defmacro local-bindings
"Produces a map of the names of local bindings to their values."
[]
(let [symbols (map key &env)]
(zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))
(let [two 2
three (inc two)]
(into {} (map (fn [[k v]] [(keyword k) v]) (local-bindings))))
{:two 2, :three 3}
Note that this will also capture the bindings introduced by any outer let forms...