This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-05-29
Channels
- # architecture (2)
- # bangalore-clj (2)
- # beginners (177)
- # boot (1)
- # cider (36)
- # clara (15)
- # cljs-dev (30)
- # cljs-experience (6)
- # cljsrn (7)
- # clojure (94)
- # clojure-argentina (2)
- # clojure-brasil (1)
- # clojure-dusseldorf (6)
- # clojure-greece (1)
- # clojure-italy (18)
- # clojure-norway (4)
- # clojure-quebec (1)
- # clojure-russia (28)
- # clojure-sg (3)
- # clojure-spec (12)
- # clojure-turkiye (1)
- # clojure-uk (12)
- # clojurescript (169)
- # code-reviews (4)
- # community-development (2)
- # core-async (6)
- # core-matrix (6)
- # cursive (35)
- # datomic (18)
- # devcards (4)
- # euroclojure (1)
- # hoplon (2)
- # keechma (4)
- # klipse (2)
- # leiningen (1)
- # luminus (16)
- # mount (1)
- # off-topic (34)
- # om (31)
- # pedestal (6)
- # re-frame (14)
- # reagent (33)
- # specter (4)
- # uncomplicate (8)
- # unrepl (15)
- # untangled (24)
- # yada (25)
This is the first time i have been like, yea, this is way harder in clojure then in python: http://www.4clojure.com/problem/53. The problem is to much about keeping track of state to have a declartive solution that isn’t actual less descriptive then an imperative one.
The best bet is probably to fall back to just reduce.
ok if we can turn [[0 1] [1 2] [2 3]]
into [0 1 2 3]
in an elegant way we can redeem clojure on this one 🙂
never-mind, even with those changes my function doesn’t work. You need to keep track of to much state for it to be a good fit imo.
@drewverlee for things that truly need state across args, that work across an input sequence, I find reduce tends to work nicely
that's what I used in my answer to that question (I admit, I answered it a long time ago and I need to re-read to make sure I still think that's the most elegant - but it's not a super complex block of code)
@drewverlee I don't know, I think mfikes's solution was pretty elegant...
imho mine is better 😛
I haven’t seen a solution yet where I (personally) was like yea, thats better then what i would do in an imperative style. But maybe i need to review them more closely 🙂
@noisesmith whats your handle on 4clojure? if you dont mind me asking
noisesmith
some of my answers are crap, but I think my answer for that one is decent
@drewverlee here's a crack at it:
(fn [y]
(let [firsts (fn [x]
(map #(subvec x 0 %)
(range (inc (count x)))))
;; [1 2 0] => ([] [1] [1 2] [1 2 0])
rests (fn [x]
(loop [a x acc []]
(if (not (empty? a))
(recur (rest a) (conj acc a))
acc)))
;; [1 2 0] => [[1 2 0] (2 0) (0)]
consecutive? (fn [x]
(every? #(= -1 %)
(map #(apply - %)
(partition 2 1 x))))
;; [1 2 0] => false
consecutives (fn [x]
(filter
#(and (consecutive? %) (apply < %))
(filter #(> (count %) 1)
(apply concat (map rests (firsts x))))))
;; [1 2 0] => ([1 2])
longest-consecutive (fn [x]
(vec (last (sort-by count (consecutives x)))))]
;; [1 2 0] => [1 2]
(longest-consecutive y)))
Can probably be made a lot prettier, but the method is there@noisesmith i submit a patch to change =
to >
so it works over any increase amount. Other then that, yea, thats exactly how i was thinking this should be done. Thanks.
What kills my solution is that partition-by cuts a value i need (the last value in the seq). Essentially you end up with a structure where some elements have different meanings and you can’t map and filter your way to victor. Hense reduce :0
I could imagine a lazy-seq version built on rests
(which iirc is just (iterate rest l)
)
oh man I might have to re-solve this now
I’m just looking at the soultions on 4clojure and the one thing they have in common, is, for the most part, they have nothing in common. Which, i think, is an undesirable trait. As multiple solutions to a problem as it indicates a lack of a clear way to solving the problem. I’m following like 50 random people that all finished 156 questions, maybe i should have been more discerning in my followers though as i do like noises the best at this point.
@john you follow people then after you solve the problem you can see other solutions.
if 4clojure accepted as-> this would be my new answer:
(defn longest-increasing [l]
(let [tails (take-while seq (iterate rest l))
adj #(= (inc (first %)) (second %))]
(apply max-key count
(map #(-> %
(->> (partition 2 1)
(split-with adj))
(as-> [a b]
(concat a (take 1 b)))
(->> (map first)))
tails))))
it works, and it's all lazy-seq ops instead of imperative
ill have to take a look at that in the morning thanks though
hmm - how about this one (it passes unlike my last silly one)
(fn longest-increasing [l]
(letfn [(tails [s] (take-while seq (iterate rest (concat l [nil]))))
(adj [[a b]] (= (inc a) b))
(these-and-1 [[a b]] (concat a (take 1 b)))
(take-run [nums]
(->> nums
(partition 2 1)
(split-with adj)
(these-and-1)
(map first)))
(lonely [l] (= 1 (count l)))]
(apply max-key count
(->> (tails l)
(map take-run)
(cons [])
(remove lonely)))))
it's less concise, but may be more clear
Here's a version with some transducing:
(fn longest-increasing [x]
(let [rests (fn [y] (take (count y) (iterate rest y)))]
(vec
(last
(sort-by count
(filter (fn [y] (and (> (count y) 1)
(every? #(= -1 %)
(map #(apply - %) (partition 2 1 y)))))
(into []
(comp
(map reverse)
(mapcat rests)
(map reverse))
(rests x))))))))
couldn't the filter be inside the comp of the transducer?
I don't get it
it would just be the last thing in the comp
(fn longest-increasing [x]
(let [rests (fn [y] (take (count y) (iterate rest y)))]
(vec
(last
(sort-by count
(into []
(comp
(map reverse)
(mapcat rests)
(map reverse)
(filter (fn [y]
(and (> (count y) 1)
(every? #(= -1 %)
(map #(apply - %)
(partition 2 1 y)))))))
(rests x)))))))
(vec
(last
(sort-by count
can be replaced with (apply max-key count
(plus removing a couple close parens at the end)equality doesn't care about vec vs. lazyseq
+user=> (doc max-key)
-------------------------
clojure.core/max-key
([k x] [k x y] [k x y & more])
Returns the x for which (k x), a number, is greatest.
nil
so (max-key count a b c)
calls count on each of a,b,c and returns the one for which count had the largest result
(fn longest-increasing [x]
(let [rests #(take (count %) (iterate rest %))]
(->> (rests x)
(sequence
(comp
(map reverse)
(mapcat rests)
(map reverse)
(filter #(every? #{-1} (map (partial apply -) (partition 2 1 %))))
(map #(if (< 1 (count %)) (vec %) []))))
(apply max-key count))))
wouldn't that miss increasing subsequences in the middle of a collection?
well, the max-key on the outer level means the whole thing can't be lazy, even if individual things inside can be
it's a non-lazy question by definition "thing that is largest by this score"
oh right because of how you use rests
the vec call doesn't do anything in the context of this question btw
Is it possible for the reader to lazily eval regex? The following breaks in clj and cljs but each regex is valid in it's own lang `(def reggy #?(:clj #"(?s)http://HAT.CAT" :cljs #"BAT\0MAN"))`
@gmercer not an oddity, definitely a pitfall of reader conditionals: all branches are read so each branch must be readable even if not runnable.
I need a better example on the cljs side .. where java can handle the string but not the regex 😉 Thanks - that provides the "laziness" I need
Does it matter they type of the returning collections?
(defn rotate [s]
(cons s (map concat (rest (rests s)) (reverse (rest (map reverse (rests (reverse s))))))))
Here's another with the rests built in:
(defn rotations [s]
(-> (mapcat
(rest (take (count s) (iterate rest s)))
(reverse (rest (map reverse (take (count s) (iterate rest (reverse s)))))))
(cons s)))
Came up with a cleaner version of problem 53 transducer solution:
(fn longest-increasing [number-sequence]
"Finds the longest subsequence of consecutively increasing numbers."
(let [longest #(apply max-key count %)
increasing? #(every? #{-1} (map (partial apply -) (partition 2 1 %)))
long-enough #(if (< 1 (count %)) (vec %) [])
rests #(take (count %) (iterate rest %))
exploder (comp (map reverse) (mapcat rests) (map reverse))
increasers (comp exploder (filter increasing?) (map long-enough))
increasing #(sequence increasers (rests %))]
(-> number-sequence (increasing) (longest))))
Which is more performant. But 4clojure doesn't recognize transducers yet, so you can do this instead:
(fn longest-increasing [number-sequence]
(let [longest #(apply max-key count %)
increasing? #(every? #{-1} (map (partial apply -) (partition 2 1 %)))
long-enough #(if (< 1 (count %)) (vec %) [])
rests #(take (count %) (iterate rest %))
exploder #(->> % (map reverse) (mapcat rests) (map reverse))
increasers #(->> % (exploder) (filter increasing?) (map long-enough))
increasing #(-> (rests %) increasers)]
(-> number-sequence (increasing) (longest))))
Nicely self-documenting. But if you're more into terse:
(fn longest-increasing [x]
(->> (take (count x) (iterate rest x))
(map reverse)
(mapcat #(take (count %) (iterate rest %)))
(map reverse)
(filter #(every? #{-1} (map (partial apply -) (partition 2 1 %))))
(map #(if (< 1 (count %)) (vec %) []))
(apply max-key count)))
@vitruvia but looking at your code, (cons rotated (rotations rotated))
seems to pass rotated
back into the top-level function, but rots
is never passed back in.
Usually, when using that method, (cons rotated (rotations rotated))
would be in the tail position, so the results of the recursion are actually chained together.
when something is recursive and you get a stack overflow, that means your stop condition isn't being hit
(usually)
I'm not sure what you mean @john . Rots is meant to get called unless the rotation count is the same as the number of elements in the sequence
@vitruvia Try to imagine what the value of rotated in rotated (concat (rest a-seq) (vector (first a-seq))
will be on the second iteration, where only the rest of rotated is passed in.
rots
is meant to concatenate all the rotation, so (count rots)
should return the number of all rotations so far, no? Then if it is equal to (count a-seq)
it should stop
@john I don't see the mistake. On the recursive call I am sending the whole of rotated, not just the rest
but @noisesmith does seem to be right on that the termination condition is not being reached
maybe (count rots)
doesn't return what I think it does? I don't know how to debug on clojure or I would check it
@vitruvia nevertheless, in (= (count a-seq) (count rots))
, you're treating a-seq
as if it is still the original size of a-seq
. I'm not sure how that's going to be possible, if you're passing in a new rotated
each time. rots
and a-seq
may never line up.
and with (if (empty? a-seq) (sequence a-seq) ...
if a-seq
is empty, sequence
would return nil
.
@vitruvia this might be the ticket:
(defn rotations [a-seq]
(if (= (count (first a-seq)) (count a-seq))
(sequence a-seq)
(rotations (concat (rest a-seq) (vector (first a-seq))))))
The test case required that if the sequence is empty it returns ()
. That is the only way I found of doing that (worked on other functions).
Also I don't see the problem in presuming that a-seq
has the same length of the previous, since rotated
always keeps the length intact.
Here are a few test cases
(rotations []) ;=> (())
(rotations [1 2 3]) ;=> ((1 2 3) (2 3 1) (3 1 2))
(rotations [:a :b]) ;=> ((:a :b) (:b :a))
; The order of rotations does not matter.
(rotations [:a :b]) ;=> ((:b :a) (:a :b))
(rotations [1 5 9 2]) ;=> ((1 5 9 2) (2 1 5 9) (9 2 1 5) (5 9 2 1))
(count (rotations [6 5 8 9 2])) ;=> 5
@vitruvia this might work
(defn rotations [a-seq]
(if-not (coll? (first a-seq))
(rotations [a-seq (vec (concat (rest a-seq) (vector (first a-seq))))])
(if (= (count (first a-seq)) (count a-seq))
a-seq
(rotations (conj a-seq (#(vec (concat (rest %) (vector (first %)))) (last a-seq)))))))
@vitruvia Here's a version that returns lists:
(defn rotations [a-seq]
(if-not (coll? (first a-seq))
(rotations [a-seq (concat (rest a-seq) (list (first a-seq)))])
(if (= (count (first a-seq)) (count a-seq))
(apply map list a-seq)
(rotations (conj a-seq (#(concat (rest %) (list (first %))) (last a-seq)))))))
I like this version better though:
(defn rotations [s]
(->> (map concat
(rest (take (count s) (iterate rest s)))
(reverse (rest (map reverse (take (count s) (iterate rest (reverse s)))))))
(apply map list (concat s))))
@vitruvia this version is more explicit:
(defn rotations [s]
"Provides all rotations of a sequence."
(let [rests #(take (count %) (iterate rest %))
other-halfs #(reverse (rest (map reverse (rests (reverse %)))))
whole-thing #(apply map list (concat %))]
(->> (map concat (rest (rests s)) (other-halfs s))
(whole-thing))))
if the first item in a-seq
was a number, then we were on the first iteration. If it was a coll, we were on a subsequent iteration.
(defn rotations [s]
"Provides all rotations of a sequence."
(if (empty? s)
s
(let [rests #(take (count %) (iterate rest %))
other-halfs #(reverse (rest (map reverse (rests (reverse %)))))
whole-thing #(apply map list (concat %))]
(->> (map concat (rest (rests s)) (other-halfs s))
(whole-thing)))))
I wasn't checking if a-seq was a coll but I was forcing it to become a coll by (sequence a-seq)
I don't mean for sequence
. Notice how mine had two recursion branches? One for when we initially provide a sequence of numbers. The other for when we provide a sequence of sequences of numbers.
All iterations subsequent to the first pass in a sequence of sequences, rather than a sequence of numbers we pass in on the first iteration.
Take is pretty basic. You should def catch up on that one. Very useful. Iterate is a little more advanced.
I just have read on take, but I think the exercise is meant to be done with the tools given so far =(
You can replace the (iterate rest %)
with something like
(fn [x]
(loop [a x acc []]
(if (not (empty? a))
(recur (rest a) (conj acc a))
acc)))
Take can probably be written in something else, but I'd be surprised if you weren't allowed to use it.
Nah its an online exercise, it is not gonna fail, just trying to see if I can do it with something else
@vitruvia In real world code, I'd recommend decomposing these kinds of functions into smaller functions, which can be more easily tested:
(defn heads [x] (rest (take (count x) (iterate rest x))))
(defn tails [x] (reverse (map reverse (heads (reverse x)))))
(defn heads-and-tails [x] (map concat (heads x) (tails x)))
(defn rotations [x] (if (empty? x) '(()) (map seq (cons x (heads-and-tails x)))))
(rotations [1 2 3])
;=> ((1 2 3) (2 3 1) (3 1 2))
@lepistane lots. For react-native on android/ios: http://cljsrn.org/
Here's a list of TodoMVC examples using various CLJS frameworks: https://github.com/gadfly361/cljs-todomvc
Honestly, searching github with "cljs" will get you lots of examples. No prob. Another cool example is the documentation for re-com: http://re-demo.s3-website-ap-southeast-2.amazonaws.com It's more for desktop oriented web-apps. But a pretty complete widget library and lots of good examples that run right in the documentation.
for re-com, there are a number of 'considerations' called out in the read-me here: https://github.com/Day8/re-com
could somebody explain why it's necessary to have 'var' in this snippet?
(defn -main []
(jetty/run-jetty
(-> handler var wrap-nocache wrap-reload)
{:port 3000
:join? false}))
the book cryptically says "This is necessary to ensure that the var object containing the current handler function is returned. If we used the handler
instead, then the app would only see the original value of the function and changes would not be reflected." but I'm unclear on what the difference is between "the var object" and "the handler"when a function is passed as an argument to another function, redefining the function doens't change the behavior of the other function if it is still running
if you use a var as a function, clojure looks up the latest value of the var each time you call it, and uses that
a var is a mutable container that belongs to a namespace, and holds whatever value def or defn most recently put in it
aren't we passing the result of the ->
macro to run-jetty
, though, which is handler
inside two middleware closures?
it's the var that holds handler
that's what calling var on handler does
it replaces it with the var
(var f) says "don't look up the value of f, just give me the var containing it"
and then that var is passed into two middleware closures
wrap-reload works regardless, but without the var quote you would never use the new definition that wrap-reload generates
a much more reliable alternative is to clojure.tools.namespace/refresh which actually breaks down each namespace and recreates it, thus deleting old definitions and fixing certain issues regarding multimethods and protocols, but this requires some system for easy reloading of the app state (eg. stuartsierra/component or integrant) so it's typically not a default setup
I'm using emacs+CIDER+nrepl. I just added some new dependencies. what's the best way to recompile my project?
if you have clj-refactor, you could also try this: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-add-project-dependency