How to use nested for in clojure [closed] - clojure

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a list of lists,((1,2,3,4)(2,3,4,5)(3,4,5,6)) and I want to implement for loop in clojure. I want to first get the first list i.e, (1,2,3,4) and then again implement for loop in this to get each element.
Thank you

Clojure's for is not a looping structure.
It is a macro that generates a combination of the necessary nested
map, filter, and take-while calls. These operate on sequences.
It always produces a lazy sequence.
From your question, I infer that you make sense of (1), but make nothing of (2) or (3). If you want to use Clojure effectively, understand their terms, and your question will answer itself.

If you want to loop through all the numbers as if they were in one list you can flatten the list:
> (flatten `((1,2,3,4)(2,3,4,5)(3,4,5,6)))
(1 2 3 4 2 3 4 5 3 4 5 6)
After that, to do an action against all the numbers you could use any function that takes in a list of numbers. Here's an example using reduce and +:
> (reduce + (flatten `((1,2,3,4)(2,3,4,5)(3,4,5,6))))
42

A for expression is meant to transform a collection into another collection, which is the return value. A doseq expression is meant to have side effects and always returns nil.
Here is some example code & results. Note that I usually prefer forv instead of for, as forv is not lazy and always returns results in a vector.
(ns xyz
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(def data
'[ (1,2,3,4)
(2,3,4,5)
(3,4,5,6) ] )
(newline)
(println "forv demo")
(spyx (forv [i [1 2 3]]
(spyx i )))
(newline)
(println "doseq demo")
(spyx (doseq [i [1 2 3]]
(spyx i )))
(println "-----------------------------------------------------------------------------")
(newline)
(println "for 1d")
(println "final result ="
(forv [sub-list data]
(spyx sub-list )))
(newline)
(println "for 2d")
(println "final result ="
(forv [sub-list data
int-val sub-list]
(spyx int-val )))
(newline)
(newline)
(println "for 2d-2")
(println "final result ="
(forv [sub-list data]
(forv [int-val sub-list]
(spyx int-val ))))
(newline)
(println "-----------------------------------------------------------------------------")
(newline)
(println "doseq 1d")
(doseq [sub-list data]
(println "sub-list =" sub-list ))
(newline)
(println "doseq 2d")
(doseq [sub-list data]
(doseq [int-val sub-list]
(spyx int-val )))
(newline)
(println "doseq 2d-2")
(doseq [sub-list data
int-val sub-list]
(spyx int-val ))
The first shows that both loop over data, but for/forv return a new collection, while doseq returns nil and is only intended for side effects.
forv demo
i => 1
i => 2
i => 3
(forv [i [1 2 3]] (spyx i)) => [1 2 3]
doseq demo
i => 1
i => 2
i => 3
(doseq [i [1 2 3]] (spyx i)) => nil
The second part shows how for can be used for 1-d or 2-d loops. Also, a single forv statement can to 2-d looping, or you can nest the forv statements. Notice the difference in nesting in the final result for the 3 cases.
-----------------------------------------------------------------------------
for 1d
sub-list => (1 2 3 4)
sub-list => (2 3 4 5)
sub-list => (3 4 5 6)
final result = [(1 2 3 4) (2 3 4 5) (3 4 5 6)]
for 2d
int-val => 1
int-val => 2
int-val => 3
int-val => 4
int-val => 2
int-val => 3
int-val => 4
int-val => 5
int-val => 3
int-val => 4
int-val => 5
int-val => 6
final result = [1 2 3 4 2 3 4 5 3 4 5 6]
for 2d-2
int-val => 1
int-val => 2
int-val => 3
int-val => 4
int-val => 2
int-val => 3
int-val => 4
int-val => 5
int-val => 3
int-val => 4
int-val => 5
int-val => 6
final result = [[1 2 3 4] [2 3 4 5] [3 4 5 6]]
-----------------------------------------------------------------------------
The doseq syntax is similar to for, but only the side effects like print are visible to the outside world. doseq always returns nil. This also implies there is no nesting difference in the return value like with forv.
doseq 1d
sub-list = (1 2 3 4)
sub-list = (2 3 4 5)
sub-list = (3 4 5 6)
doseq 2d
int-val => 1
int-val => 2
int-val => 3
int-val => 4
int-val => 2
int-val => 3
int-val => 4
int-val => 5
int-val => 3
int-val => 4
int-val => 5
int-val => 6
doseq 2d-2
int-val => 1
int-val => 2
int-val => 3
int-val => 4
int-val => 2
int-val => 3
int-val => 4
int-val => 5
int-val => 3
int-val => 4
int-val => 5
int-val => 6
Note that your project.clj will need to include the following for spyx to work
:dependencies [
[tupelo "0.9.10"]

Related

passing partitions to another function in clojure

I am just started clojure but I can't seem to figure out using/creating higher order functions.
I have partitioned a collection and I want to pass that into another function that will do something to the window of items. I am not sure how to go about doing this.
(def foo [:a :b :c :d :e])
(partition 3 1 foo)
;;=> ((:a :b :c) (:b :c :d) (:c :d :e))
(defn bar [start next end])
I think the basic outline would be.
(defn faz [collect]
(partition 3 1 collect)
;;maybe do here before passing
(bar stand next end)
)
I might be getting ahead of myself but I also see there are other functions like reduce and apply they can do something similar right? Although, most examples I see have it so they perform operations on two items at a time which are similar to (partition 2 1 foo)
You can do something like
(defn bar [start next end])
(defn faz [collect]
(let [partitions (partition 3 1 collect)]
(apply bar partitions)
))
or if you want to call bar directly, you can use destructuring
(defn bar [start next end])
(defn faz [collect]
(let [partitions (partition 3 1 collect)
[start next end] partitions]
(bar start next end)
))
Your question is general and there is more ways to achieve this, based on expected result and used function.
If you want to return sequence of results, use map and apply:
(defn results-for-triplets [collect]
(map #(apply + %) (partition 3 1 collect)))
(results-for-triplets [1 2 3 4 5])
=> (6 9 12)
For better readability, you can use ->> macro.
(defn results-for-triplets [collect]
(->> collect
(partition 3 1)
(map #(apply + %))))
(results-for-triplets [1 2 3 4 5])
=> (6 9 12)
You can avoid apply, if your function destructures passed sequence:
(defn sum3 [[a b c]]
(+ a b c))
(defn results-for-triplets [collect]
(->> collect
(partition 3 1)
(map sum3)))
(results-for-triplets [1 2 3 4 5])
=> (6 9 12)
If you want to call function for side effect and then return nil, use run!:
(defn print3 [[a b c]]
(println a b c))
(defn results-for-triplets [collect]
(->> collect
(partition 3 1)
(run! print3)))
(results-for-triplets [1 2 3 4 5])
1 2 3
2 3 4
3 4 5
=> nil

why Clojure conatins? behave so strangely? [duplicate]

This question already has answers here:
Issue with Clojure 'contains'
(3 answers)
Closed 1 year ago.
Why clojure output true fo first one and false for the second one
(def myset [3 5 7 11 13 17 19])
(defn check-n
[n]
(contains? myset n))
(check-n 1)
(check-n 20)
contains? is function for checking keys in collection. It can be used with map:
(contains? {:a 1 :b 2} :a)
=> true
(contains? {:a 1 :b 2} :c)
=> false
or with vector- in this case, it checks whether vector contains given index:
(contains? [1 2 3] 0)
=> true
(contains? [1 2 3] 3)
=> false
If you want to check occurence of number, use .contains from Java:
(.contains [1 2 3] 3)
=> true
or some with set used as predicate:
(some #{3} [1 2 3])
=> 3
(some #{4} [1 2 3])
=> nil

Clojure: I am trying to use 'some' instead of 'doseq' but I am not really sure how to use it

How to replace the "doseq" with "some" in this scenario. I am new to clojure.
(def handle (atom ()))
;; #'user/players
;; conjoin a keyword into that list
(swap! handlers conj [:report "handles"])
;;=> ([:report "handles"])
;; conjoin a second keyword into the list
(swap! handlers conj [:demo "handles2"])
;;=> ([:demo "handles2"] [:report "handle"])
(doseq [[a b] #handlers] (println a "--" b))
;;=> :demo -- handles2
;;=> :report -- handles
The Clojure docs for doseq and some are loaded with examples that can help you figure out what to use and how to use it.
There are several things I don't know about your situation, but maybe I can help with these examples.
some
Detects if something exists based on a condition. Returns the result of the predicate, if the predicate returns truthy.
Takes a predicate and a collection
Predicate examples:
#(= 2 %) ; Equals 2
(fn [val] (= val "user3438838")) ; equals your username
Collection examples:
[1 2 3 4 5 6 7 8]
["user3438838" "programs" "in" "Clojure"]
Let's evaluate the combinations of these:
(some #(= 2 %) [1 2 3 4 5 6 7 8]) ; => true
(some #(= 2 %) ["user3438838" "programs" "in" "Clojure"]) ; => nil
(some (fn [val] (= val "user3438838")) [1 2 3 4 5 6 7 8]) ; => nil
(some (fn [val] (= val "user3438838")) ["user3438838" "programs" "in" "Clojure"]) => true
doseq
Implement an expression for all elements of a sequence, for side effects. This is the first function I looked for when coming from JS, but it's usually not the right thing (it doesn't take advantage of lazily evaluating, decreasing performance). Generally want to apply a recursive expression, like loop with recur, but doseq may make sense here.
We'll take the same approach as with some
doseq takes (a) sequence(s) and and expression that ostensibly uses each element of the sequence.
Sequence examples:
[x ["user3438838" "programs" "in" "Clojure"]]
[x [1 2 3 4 5 6 7 8]]
; Note: Can use multiple [x (range 10) y (range 10 20)]
Body expression examples:
(println x)
(println (str "The number/word is: " x))
And now we'll combine these:
(doseq [x ["user3438838" "programs" "in" "Clojure"]] (println x)) ; Prints "user3438838\nprograms\nin\nClojure"
(doseq [x ["user3438838" "programs" "in" "Clojure"]] (println (str "The number/word is: " x))) ; Prints "The word is: user3438838 ..."
(doseq [x [1 2 3 4 5 6 7 8]] (println x)) ; Prints "1\n2\n3\n4\n5\n6\n7\n8
(doseq [x [1 2 3 4 5 6 7 8]] (println (str "The number/word is: " x))) ; Prints "The number/word is: 1 ..."
Hope this helps you understand the two.
And if you're new, I think the go-to book for learning Clojure is Daniel Higginbotham's (2015) Clojure for the Brave and True where he describes some (and not doseq b/c you generally want to use lazily/recursively evaluated expressions).

lang.LazySeq cannot be cast to IPersistantVector

In the process of learning Clojure.
I have a function to draw a random card from the deck
(defn draw-random-card
[cards]
(let [card (rand-nth cards)
index (.indexOf cards card)]
{:card card :remaining-cards (concat (subvec cards 0 index)
(subvec cards (inc index)))}))
Running it:
(draw-random-card ["Ace" 2 3 4 5 6 7 8 9 10 "Jack" "Queen" "King"])
=> {:card 4, :remaining-cards ("Ace" 2 3 5 6 7 8 9 10 "Jack" "Queen" "King")}
I'd like to call it twice and get 2 cards out but the second time it calls it, it will pass the reduced deck from the first call.
IN the end I'd like to have the 2 cards and the reduced deck to use later.
I would have thought I could do something like:
(def full-deck ["Ace" 2 3 4 5 6 7 8 9 10 "Jack" "Queen" "King"])
(let [first-draw (draw-random-card full-deck)
first-card (:drawn-card first-draw)
second-draw (draw-random-card (:remaining-cards first-draw))
second-card (:drawn-card second-draw)
remaining-deck (:remaining-cards second-draw)]
(println "First card: " first-card)
(println "Second card: " second-card)
(println "Remaining deck:" remaining-deck))
However, I'm obviously doing something dumb here as I get the error:
Execution error (ClassCastException) at aceyducey.core/draw-random-card (form-init3789790823166246683.clj:5).
clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentVector
I think the problem is in the line
second-draw (draw-random-card (:remaining-cards first-draw))]
Because remaining-cards isn't a vector?
Which means
concat (subvec cards 0 index)
(subvec cards (inc index)))}))
Isn't returning a vector? Rather a lazy sequence ???
But at this point I'm lost.
Help!
#amalloy makes a good point: the Clojure built-in function shuffle is probably what you want:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test) )
(def cards [:ace 2 3 4 5 6 7 8 9 10 :jack :queen :king] )
(dotest
(dotimes [i 3]
(spyx (shuffle cards))))
=>
Testing tst.demo.core
(shuffle cards) => [:king :jack 6 2 9 10 :ace 4 8 5 3 :queen 7]
(shuffle cards) => [2 :jack 7 9 :queen 8 5 3 4 :ace 10 :king 6]
(shuffle cards) => [7 :queen :jack 4 3 :king 6 :ace 2 10 5 8 9]
This and much more is available at the Clojure CheatSheet. Be sure to bookmark it and always keep a browser tab open with it.
concat returns a lazy sequence. You can coerce it into a vector by using:
(vec (concat ...))
Here is the full code with a test:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn draw-random-card
[cards]
(let [card (rand-nth cards)
index (.indexOf cards card)]
{:drawn-card card :remaining-cards (vec (concat (subvec cards 0 index)
(subvec cards (inc index))))}))
(def full-deck ["Ace" 2 3 4 5 6 7 8 9 10 "Jack" "Queen" "King"])
(dotest
(let [first-draw (draw-random-card full-deck)
first-card (:drawn-card first-draw)
second-draw (draw-random-card (:remaining-cards first-draw))
second-card (:drawn-card second-draw)
remaining-deck (:remaining-cards second-draw)]
(println "First card: " first-card)
(println "Second card: " second-card)
(println "Remaining deck:" remaining-deck))
)
and result:
-------------------------------
Clojure 1.10.0 Java 12
-------------------------------
Testing tst.demo.core
First card: Queen
Second card: King
Remaining deck: [Ace 2 3 4 5 6 7 8 9 10 Jack]
Update:
To be specific, the problem was the call to subvec in the 2nd iteration of your code. Here is an example:
(dotest
(let [vals (vec (range 10)) ; a vector
s1 (subvec vals 2 4) ; so `subvec` works
s2 (subvec vals 6) ; and again
lazies (concat s1 s2)] ; creates a lazy sez
(is= [2 3] (spyxx s1))
(is= [6 7 8 9] (spyxx s2))
(is= [2 3 6 7 8 9] (spyxx lazies))
(throws? (subvec lazies 0 2)))) ; ***** can't call `subvec` on a non-vector (lazy sequence here) *****
with result:
s1 => <#clojure.lang.APersistentVector$SubVector [2 3]>
s2 => <#clojure.lang.APersistentVector$SubVector [6 7 8 9]>
lazies => <#clojure.lang.LazySeq (2 3 6 7 8 9)>
so by coercing the output of concat to a vector, the call to subvec succeeds on the next time through the function.
So, in hindsight, a better solution would have been to coerce the input to a vector like so:
(let [cards (vec cards)
card (rand-nth cards)
index (.indexOf cards card)]
{:drawn-card card
:remaining-cards (vec (concat (subvec cards 0 index)
(subvec cards (inc index))))}))
Update #2
If you don't want to coerce your input to a vector, you can use the .subList() function via Java interop:
(dotest
(spyxx (.subList (concat (range 5) (range 10 15)) 5 10))
(spyxx (.subList (range 10) 2 5))
(spyxx (.subList (vec (range 10)) 2 5))
(spyxx (subvec (vec (range 10)) 2 5))
(throws? (subvec (range 10) 2 5))) ; *** not allowed ***
with result
(.subList (concat (range 5) (range 10 15)) 5 10)
=> <#java.util.ArrayList$SubList [10 11 12 13 14]>
(.subList (range 10) 2 5)
=> <#java.util.Collections$UnmodifiableRandomAccessList [2 3 4]>
(.subList (vec (range 10)) 2 5)
=> <#clojure.lang.APersistentVector$SubVector [2 3 4]>
(subvec (vec (range 10)) 2 5)
=> <#clojure.lang.APersistentVector$SubVector [2 3 4]>

Why do I get NPE in the following code?

The following code executes as expected but gives a NullPointerException at the end. What am I doing wrong here?
(ns my-first-macro)
(defmacro exec-all [& commands]
(map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands))
(exec-all
(cons 2 [4 5 6])
({:k 3 :m 8} :k)
(conj [4 5 \d] \e \f))
; Output:
; Clojure 1.2.0-master-SNAPSHOT
; Code: (cons 2 [4 5 6]) => Result: (2 4 5 6)
; Code: ({:k 3, :m 8} :k) => Result: 3
; Code: (conj [4 5 d] e f) => Result: [4 5 d e f]
; java.lang.NullPointerException (MyFirstMacro.clj:0)
; 1:1 user=> #<Namespace my-first-macro>
; 1:2 my-first-macro=>
(For properly syntax highlighted code, go here.)
Take a look at the expansion that is happening:
(macroexpand '(exec-all (cons 2 [4 5 6])))
=>
((clojure.core/println "Code: " (quote (cons 2 [4 5 6])) "\t=>\tResult: " (cons 2 [4 5 6])))
As you can see, there is an extra pair of parentheses around your expansion, which means that Clojure tries to execute the result of the println function, which is nil.
To fix this I'd suggest modifying the macro to include a "do" at the front, e.g.
(defmacro exec-all [& commands]
(cons 'do (map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands)))
Since the OP asked for other possible ways of writing this macro (see comments on the accepted answer), here goes:
(defmacro exec-all [& commands]
`(doseq [c# ~(vec (map (fn [c]
`(fn [] (println "Code: " '~c "=> Result: " ~c)))
commands))]
(c#)))
This expands to something like
(doseq [c [(fn []
(println "Code: " '(conj [2 3 4] 5)
"=> Result: " (conj [2 3 4] 5)))
(fn []
(println "Code: " '(+ 1 2)
"=> Result: " (+ 1 2)))]]
(c))
Note that the fn forms whose values will be bound to c are collected in a vector at macro-expansion time.
Needless to say, the original version is simpler, thus I think (do ...) is the perfect fix. :-)
Example interaction:
user=> (exec-all (conj [2 3 4] 5) (+ 1 2))
Code: (conj [2 3 4] 5) => Result: [2 3 4 5]
Code: (+ 1 2) => Result: 3
nil