This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-03
Channels
- # announcements (2)
- # babashka (15)
- # beginners (40)
- # calva (11)
- # cherry (2)
- # cider (3)
- # cljsrn (2)
- # clojure (37)
- # clojure-austin (4)
- # clojure-europe (2)
- # clojurescript (16)
- # core-async (1)
- # datomic (25)
- # hyperfiddle (18)
- # jobs-discuss (9)
- # nbb (7)
- # off-topic (19)
- # pathom (6)
- # podcasts-discuss (4)
- # portal (37)
- # practicalli (1)
- # re-frame (11)
- # releases (1)
- # scittle (13)
- # shadow-cljs (6)
(def phone-prj-list [{"1001" "red"}
{"1005" "blue"}
{"1001" "black"}
{"1004" "yellow"}
{"1005" "green"}])
;I want to get result like this
{"1001" "red,black"
"1005" "blue,green"
"1004" "yellow"}
;; this is my code. but the result is not right
(reduce (fn [x y]
(let [k (key (first y))
value (val (first y))]
(prn "x=" x ",y=" y ",contains key:" k ," conains:" (contains? x key) )
(if (contains? x key)
(update x k #(str % "," value))
(assoc x k value)))) {} phone-prj-list)
;; "x=" {} ",y=" {"1001" "red"} ",contains key:" "1001" " conains:" false
;; "x=" {"1001" "red"} ",y=" {"1005" "blue"} ",contains key:" "1005" " conains:" false
;; "x=" {"1001" "red", "1005" "blue"} ",y=" {"1001" "black"} ",contains key:" "1001" " conains:" false
;; "x=" {"1001" "black", "1005" "blue"} ",y=" {"1004" "yellow"} ",contains key:" "1004" " conains:" false
;; "x=" {"1001" "black", "1005" "blue", "1004" "yellow"} ",y=" {"1005" "green"} ",contains key:" "1005" " conains:" false
;; {"1001" "black", "1005" "green", "1004" "yellow"}
why {"1001" "red", "1005" "blue"}
contains "1001" return falseThe name of your variable is k
, but you call (contains? x key)
, searching for key
function.
You can also write something like this:
(update-vals
(->> phone-prj-list
(map first)
(group-by key))
#(str/join "," (map val %)))
=> {"1001" "red,black", "1005" "blue,green", "1004" "yellow"}
What does 'key' refer to here?
(group-by key)
(map first phone-prj-list)
;; => (["1001" "red"] ["1005" "blue"] ["1001" "black"] ["1004" "yellow"] ["1005" "green"])Result of (map first phone-prj-list)
is a sequence of map entries, they are just printed like vectors- so you can call key
on them.
> What does 'key' refer to here? > https://clojuredocs.org/clojure.core/key
(map first phone-prj-list)
;; => (["1001" "red"] ["1005" "blue"] ["1001" "black"] ["1004" "yellow"] ["1005" "green"])
(-> (map first phone-prj-list) first)
;; => ["1001" "red"]
(-> (map first phone-prj-list) first type)
;; => clojure.lang.MapEntry
Why here type is MapEntry. It's looks like vector
["1001" "red"]You have to be pretty careful trying to make decisions based on the return from type
. There is a somewhat complex hierarchy of types, which is generally considered to be implementation detail, subject to change. Even ignoring possibility of future change, you will find the type hierarchy is different in CLJS than on the JVM (and I assume probably also different in ClojureDart and ClojureCLR).
To more specifically answer your question, we can look to the source files in the folder https://github.com/clojure/clojure/tree/master/src/jvm/clojure/lang
https://github.com/clojure/clojure/tree/master/src/jvm/clojure/lang/MapEntry.java
... MapEntry extends AMapEntry ...
https://github.com/clojure/clojure/tree/master/src/jvm/clojure/lang/AMapEntry.java
AMapEntry.java
... AMapEntry extends APersistentVector ...
https://github.com/clojure/clojure/tree/master/src/jvm/clojure/lang/APersistentVector.java
... APersistentVector ... implements IPersistentVector ...
So basically, MapEntry is derivative of vector.is there a way I can pass something like Integer/parseInt
to map
directly? Seems to only work if I wrap it in an anonymous function to invoke it like (Integer/parseInt "xyz")
That’s correct
but for this particular situation, you can use parse-long
instead
Don't know if it helps any, but you can always de-anonymize it.
(defn parseInt [x]
(Integer/parseInt x))
(map parseInt xs)
or
(let [parseInt (fn [x] (Integer/parseInt x)]
(map parseInt xs))
which is the existing parse-long
(effectively)
Is there a way to "zip" two ordered collections together to process (i.e. in a filter)? I'm looking to take 2 strings and compare them char by char.
Zipmap isn't working for me. If there are any duplicates, then it elides them.
(zipmap "ACCAGGG" "ACTATGG");; => {\A \A, \C \T, \G \G}
I'm working on this 4clojure problem:
https://4clojure.oxal.org/#/problem/32
;; Write a function which duplicates each element of a sequence.
I tried 2 variations of a solution, and the closer one (with flatten) doesn't work for one of the instances:
(fn [entry] (flatten (for [x entry] (repeat 2 x))))
How do I retain vectors within a vector? (again, I'm trying not to look at the answers)
mapcat
is likely closer to what you want here.
flatten
is nearly always the wrong answer to any problem as it takes away all structure in the result -- which is why it fails the test.
By comparison, mapcat
only "takes away" one level of structure.
You have confirmed the doc on flatten
:
Takes any nested combination of sequential things (lists, vectors,
etc.) and returns their contents as a single, flat lazy sequence.
It is a complete flattening. So flatten
does great where the desired output happens to be a completely flattened sequence, but not so great where we want ([1 2] [1 2] [3 4] [3 4]))
.
We must think about this differently, and it is a bit clever: what we really want to do with each element e1 e2
, once we have [[e1 e1][e2 e2]]
, is not to flatten that, but to flatten just one level. Sadly, flatten
does not take a level count.
So forget flatten
, we see. Now what?
Here is a hint: Given, eg, [1 2] and [3 4], how else can we get [1 2 3 4], without using the flatten
sledgehammer? ie, solve this without flatten:
(= `(_ [1 2] [3 4]) `(1 2 3 4))
Note that that ^^ can be construed as removing exactly one level of nesting, so if we can do that without flatten, we are on the way to the next challenge: handling an arbitrarily long number of inputs. But you might be able to make that next jump sans hints, so left as exercise, hth!Thanks -- I got it to work with:
(fn [entry] (mapcat #(repeat 2 %) entry))
As I go through 4clojure, I'm trying to understand what this site and these exercises are trying to teach besides implementing Clojure functions...
• Did the site builders expect the user to already know these functions going in, regardless of level or experience in the language? (I have neither the knowledge nor experience...)
• Or, did they expect users to at least know how to search for the right answer using [search engine of choice], StackOverflow, and Clojuredocs?
Clojure core is very large -- hundreds of functions -- so these exercises are about getting you familiar with enough of them to write idiomatic Clojure, and to learn about the abstraction levels involved.
(partial mapcat #(vector % %))
is probably how I would solve it but there are lots of possibilities.
Learning the basics of Clojure doesn't take too long but mastering it at an idiomatic level is really an ongoing process. The code I write today is very, very different than the code I wrote when I got started in 2010 -- and only partly because of language changes (e.g., transducers -- Clojure 1.7, mid-2015).
You can learn a lot by studying solutions from other people- but it isn't the best tool for learning from scratch. The list of exercises isn't curated, you have no hints on what to do or which pattern you should use to solve. Unless you already have experience with some Lisp, I would recommend you to get familiar with functional concepts and patterns (map, filter, reduce, higher-order functions, recursion...), then pick some Clojure book and use 4clojure just as complement.
I would also recommend working initially from a book (Getting Clojure or Living Clojure as introductions -- then Programming Clojure and/or Clojure Applied). Online exercises are more about honing your basic skills and trying to internalize your thinking about core functions (and, yes, looking at other people's solutions can be very enlightening sometimes... and very confusing at others).
There are some better versions of my mapcat
approach in other people's solutions (such as #(mapcat vector % %)
) and there are a few instances of #(interleave % %)
which makes me go "oh, duh! yes, this problem is the very definition of interleave
" -- so even after a decade-plus, there are still core functions I don't reach for... although with interleave
, I've learned to generally avoid it b/c if the sequences are not the same length, it silently drops the extra data, so we have an interleave-all
function we use at work... but interleave
is perfect for this case since you have two identical sequences so no data dropping.
The requirement is to repeat each item contiguously (twice). So, we can imagine old-skool imperative copying of each input item twice into an output sequence. We can do this in a single pass with reduce:
reduce (fn [ys x] (conj ys x x)) []
This application of reduce relies on the fact that vectors support O(1) append.Also, Michael, re: https://clojurians.slack.com/archives/C053AK3F9/p1685895120954309?thread_ts=1685820679.297869&cid=C053AK3F9, 4clojure problems are useful prompts to research the standard library, in addition to being useful exercises to develop a finger-feel for using the language. The way I used it was alongside a book, and with a time constraint per problem. If I couldn't work it out in (say, an hour), I allowed myself to peek. Then walk away for a bit (move to other problems), and after a while, try solving it in my own way. Personally, this method helped me progress in my understanding. It is not a competition, the goal is to learn and discover.
In fact, we baked 4Clojure problems as drills into each "chapter" of an introductory Clojure workshop we've taught at IN/Clojure. https://github.com/adityaathalye/clojure-by-example/blob/master/src/clojure_by_example/ex00_introduction.clj#L252!
This approach of curating 4Clojure problems sort-of works around the fact that the original problem set isn't sequenced in any particular pedagogical structure.
@U04V70XH6 Thanks -- I'm through the first five chapters of "Getting Clojure"...albeit at a snail's pace. And it's a very palatable intro book.