This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-05-26
Channels
- # beginners (91)
- # cider (34)
- # cljsrn (6)
- # clojure (95)
- # clojure-gamedev (4)
- # clojure-serbia (7)
- # clojure-spec (5)
- # clojure-uk (27)
- # clojurescript (42)
- # data-science (1)
- # datascript (2)
- # datomic (4)
- # duct (10)
- # emacs (11)
- # fulcro (21)
- # luminus (3)
- # lumo (24)
- # off-topic (2)
- # other-languages (2)
- # ring (2)
- # shadow-cljs (39)
- # spacemacs (9)
- # tools-deps (2)
Hi, I am having a little bit of problem with lazy sequence
(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 )] (str (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 (doall (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))
I when I print I get lazy sequence.
You can look here https://stackoverflow.com/questions/50538819/lazy-sequence-clojureHi @kushalkanungo1991 -- Welcome to Clojure! You're stumbling over one of the things that people from an imperative background find most confusing when they are first learning...
for
in Clojure is not like for-loops in most other languages.
If you want to do something with side-effects -- where you essentially throw the result away -- you want doseq
:
(doseq [i sales]
(println i))
You're also approaching the overall implementation in a way that suggests an imperative, step-by-step program, using def
to "set variables" as you go through the file which is likely to lead you into problems.
Try to avoid using def
to create Vars that are bound to expressions: those all execute when you load the namespace and it's much better/safer to avoid side-effects when you load a namespace. Make all of them functions, and call them as needed.
Also look at let
as a way of setting up local bindings of name to expression values (`def` creates global names).
There are a lot of places where you're calling vec
(and str
) that you won't need as you start to understand how sequence functions are used.
Could someone please walk me through how this is calculating the result? It is the apply
that is throwing me here:
(defn add-points [& pts]
(vec (apply map + pts)))
So the result of the call (add-points [5 10] [3 8])
is [8 18]
. I'm not sure how mapping the apply is taking the first argument of each vector and adding them, and then the same with the second element of each vector.Does it already make sense to you why (map + [[5 10] [3 8]])
returns (8 18)
, or would it help to walk through that, too?
although running that in the repl gives a "cannot cast clojure.lang.PersistentVector to java.lang.Number"?
So most often you will see map
used with just 2 arguments: a function (like +
) and a sequence, e.g. (map + [3 5])
, which returns the sequence (3 5)
. Here map is causing the function calls (+ 3)
which returns 3 and (+ 5)
which returns 5.
Oh, sorry, typo on my part: I meant: (map + [5 10] [3 8])
But map
can also take any number of sequences, like this: (map + [5 10] [3 8])
. In a case like that, map will make these function calls instead: (+ 5 3)
then (+ 10 8)
, calling the function given to map with the first element of each sequence, then with the second element of each sequence, etc.
yes. And it can do that given any number of sequences, e.g. (map + [5 10] [3 8] [-1 2])
return (7 20)
So add-points
has parameters [& pts]
, where the &
means that any number of parameters can be supplied after that point, and they are all collected into a sequence and bound to the local ptr
.
pts
, I mean.
Without the apply
, the call to map
would have only 2 arguments, the function +
and the sequence pts
.
With the apply
, the call to map
now has n+1 arguments: the function +
and one argument for each element of the sequence pts
.
Glad it worked. I was making it up as I went along π
I mean, the form of the explanation, not the truth of what I was saying.
haha... yeah I got what you meant haha..... you mean you don't have answers to every possible question scripted? π
nope, tailor made just for you on the spot.
how do i use clojure 1.9?
this is my lein -v
Leiningen 2.8.1 on Java 1.8.0_171 OpenJDK 64-Bit Server VM
you could set your project.clj to use [org.clojure/clojure "1.9.0"]
instead of [org.clojure/clojure "1.8.0"]
they upped the default from 1.8 to 1.9 https://github.com/technomancy/leiningen/issues/2373
https://github.com/technomancy/leiningen/commit/e20c06bf8535078ebcf2f242833a1c61c49c6f79 is the change
i am aware of that π but is string you are using there gotten from some unsafe source - parseLong
@lockdown- You couldn't apply
Long/parseLong
to a sequence of strings -- apply
unrolls the arguments so your call would be equivalent to (Long/parseLong "1" "2")
which is not legal. parseLong
can take a second argument -- radix
-- but it must be an int
.
Perhaps you meant map
? (map #(Long/parseLong %) ["1" "2"])
Just for fun:
user=> (apply #(Long/parseLong %1 %2) ["10" 2])
2
user=>
@lockdown- That's a valid concern. Reading Clojure gets easier with experience/practice. I would probably write a small wrapper, depending on what I wanted the behavior to be on a parse failure, e.g.,
(defn ->long
([x] (->long 0))
([x default]
(if (number? x)
(long x)
(try
(Long/parseLong x)
(catch Throwable _
default)))))
Then
(map ->long ["1" "2"])
or (map #(->long % ::invalid) ["1" "not-a-number" "2"])
(the latter would produce [1 :user/invalid 2]
in the REPL)
@seancorfield like a test?
@lockdown- A test? Well, your choices with parsing are either: throw an exception or return some sort of "invalid" value. The best choice in any given situation depends on what you plan to do with the data. If you want to parse every element in a sequence and just throw away the "bad" ones, returning a flag value is useful, because then it's "just data" and you can do what you want with it. If you throw an exception, you have to decide whether you want to give up all your processing or try to catch that and does something with it etc.
If you run (map #(Long/parseLong %) some-large-collection)
and the 1,000th element can't be parsed... you get nothing (but an exception). If you return some sort of value instead of throwing an exception, you still have the option of getting those 999+ valid values back.
(you could even just return the exception itself -- as a value -- and then filter those out or report on them or whatever)
(map #(try (Long/parseLong %) (catch Throwable t t)) ["1" "not-a-number" "2"])
-- then (remove (partial instance? Throwable) ..)
would give you just the numbers and (filter (partial instance? Throwable) ..)
would give you the exceptions (to report on etc)
clojure.core
also contains Throwable->map
so you can convert an exception into a Clojure data structure for programmatic analysis etc.
@lockdown- The cheatsheet currently contains about 85% of the functions, macros, and Vars defined in core. I believe this might be the up to date list of things in core that are not in the cheatsheet: https://github.com/jafingerhut/clojure-cheatsheets/blob/master/src/clj-jvm/TODO.txt#L209-L391
@andy.fingerhut very useful thanks, (and you just cleared the meaning of the list with a commit π ) - is there any reason you specified a range in the github link?
@seancorfield convenient, I"ll keep those methods in mind
I specified a range because before I did the commit, it was the complete list of things not on the cheatsheet. Now the range is incomplete, but at least it points you in the correct part of the linked file.
I know there's a performance penalty but is there an idiomatic way to prepend to a vector and maintain the vector?
@lockdown- If the vector returned from the fn is small, I doubt it will be much of an overhead.
FWIW, I used criterium
and timed a few options:
user=> (bench (vec (cons 'foo big-vec)))
Evaluation count : 3769620 in 60 samples of 62827 calls.
Execution time mean : 16.200287 Β΅s
Execution time std-deviation : 312.821213 ns
...
user=> (bench (into ['foo] big-vec))
Evaluation count : 4092720 in 60 samples of 68212 calls.
Execution time mean : 14.736989 Β΅s
Execution time std-deviation : 72.225193 ns
...
user=>
That's with big-vec
being a 1,000-element vector.I think the answer to the original question is - no, itβs not idiomatic to pretend to a vector
Hah, true, yes, I missed that @lockdown- wanted an idiomatic way to do it -- I was more focused on the performance π