Skip to content

Instantly share code, notes, and snippets.

@dane-johnson
Last active July 26, 2023 18:14
Show Gist options
  • Save dane-johnson/cc89efe818db96cecbce43371c0655f8 to your computer and use it in GitHub Desktop.
Save dane-johnson/cc89efe818db96cecbce43371c0655f8 to your computer and use it in GitHub Desktop.
My solutions to problems on https://www.4clojure.com
;; Get to any problem by navigating to 4clojure.com/problem/[problem number]
;; 1. Nothing but the Truth
true
;; 2. Simple Math
4
;; 3. Intro to Strings
"HELLO WORLD"
;; 4. Intro to Lists
:a :b :c
;; 5. Lists: conj
'(1 2 3 4)
;; 6. Intro to Vectors
:a :b :c
;; 7. Vectors: conj
[1 2 3 4]
;; 8. Intro to Sets
#{:a :b :c :d}
;; 9. Sets: conj
2
;; 10. Intro to Maps
20
;; 11. Maps: conj
[:b 2]
;; 12. Intro to Sequences
3
;; 13. Sequences: rest
[20 30 40]
;; 14. Intro to Functions
8
;; 15. Double Down
(partial * 2)
;; 16. Hello World
#(str "Hello, " % "!")
;; 17. Sequences: map
'(6 7 8)
;; 18. Sequences: filter
'(6 7)
;; 19. Last Element
(comp first reverse)
;; 20. Penultimate Element
(comp second reverse)
;; 21. Nth Element
#(last (take (inc %2) %1))
;; 22. Count a Sequence
(fn my-count
[s]
(reduce (fn [c _] (inc c)) 0 s))
;; 23. Reverse a Sequence
#(reduce conj (list) %)
;; 24. Sum It All Up
(partial reduce +)
;; 25. Find the odd numbers
(partial filter odd?)
;; 26. Fibonacci Sequence
#(take % ((fn fib
([] (fib 0 1))
([a b]
(lazy-seq (cons b (fib b (+ a b))))))))
;; 27. Palindrome Detector
#(= (seq %) (reverse %))
;; 28. Flatten a Sequence
(fn my-flatten
[s]
(mapcat #(if (coll? %) (my-flatten %) [%]) s))
;; 29. Get the Caps
(defn get-caps
[s]
(clojure.string/join (filter #(Character/isUpperCase %) s)))
;; 30. Compress a Sequence
#(map first (partition-by identity %))
;; 31. Pack a Sequence
#(partition-by identity %)
;; 32. Duplicate a Sequence
(fn [s] (reduce #(conj %1 %2 %2) [] s))
;; 33. Replicate a Sequence
(fn [s n] (reduce #(apply conj %1 (repeat n %2)) [] s))
;; 34. Implement range
#(take (- %2 %1) (iterate inc %1))
;; 35. Local bindings
7
;; 36. Let it Be
[z 1, y 3, x 7]
;; 37. Regular Expressions
"ABC"
;; 38. Maximum value
(fn[& s](reduce #(if (< %1 %2) %2 %1) s))
;; 39. Interleave Two Seqs
;; #Note: strangely fails on the site, but will work in a more traditional Clojure environment.
(comp flatten seq zipmap)
;; 40. Interpose a Seq
(fn [v s](reduce #(conj %1 v %2) [(first s)] (rest s)))
;; 41. Drop Every Nth Item
#(apply concat (map butlast (partition %2 %2 [nil] %1)))
;; 42. Factorial Fun
#(apply * (range 1 (inc %)))
;; $43
(fn rev-interleave
[s n]
(map #(map second %) (vals (group-by #(mod (key %) n) (zipmap (range) s)))))
;; 44. Rotate Sequence
#(let [r (mod %1 (count %2))] (concat (drop r %2) (take r %2)))
;; 45. Intro to Iterate
'(1 4 7 10 13)
;; 46. Flipping out
(fn [f] (fn [& args] (apply f (reverse args))))
;; 47. Contain Yourself
4
;; 48. Intro to some
6
;; 49. Split a sequence
#(if (< (quot (count %2) 2) %1)
(partition-all %1 %2)
(reverse (map reverse (partition-all (- (count %2) %1) (reverse %2)))))
;; 50. Split by Type
#(vals (group-by class %))
;; 51. Advanced Destructuring
[1 2 3 4 5]
;; 52. Intro to Destructuring
[c e]
;; 53. Longest Increasing Sub-Seq
;; Seems hard. I'll be back
;; 54. Partition a Sequence
(fn my-partition
([n s] (my-partition n s []))
([n s g]
(if (< (count s) n)
g
(recur n (drop n s) (conj g (take n s))))))
;; 55. Count Occurrences
(fn [s] (apply merge-with + (map #(hash-map % 1) s)))
;; 56. Find Distinct Items
#(reduce (fn [s n]
(if (>= (.indexOf s n) 0)
s
(conj s n))) [] %)
;; 57. Simple Recursion
'(5 4 3 2 1)
;; 58. Function Composition
(fn [& fs] (fn [& args] (reduce #(%2 %1) (apply (last fs) args) (reverse (butlast fs)))))
;; 59. Juxtaposition
(fn [& fs] (fn [& args] (reduce #(cons (apply %2 args) %1) [] (reverse fs))))
;; 60. Sequence Reductions
(fn my-reductions
([f [first & rest]] (lazy-seq (my-reductions f first rest)))
([f red s]
(if (not (empty? s))
(cons red (lazy-seq (my-reductions f (f red (first s)) (rest s))))
(list red))))
;; 61. Map Construction
(fn [ks vs]
(->>
(map vector ks vs)
(into {})))
;; 62. Re-implement Iterate
(fn my-iterate
[f x]
(lazy-seq (cons x (my-iterate f (f x)))))
;; 63. Group a Sequence
(fn my-group-by
[f s]
(apply (partial merge-with (comp (partial into []) concat))
(map #(sorted-map (f %) [%]) s)))
;; 64. Intro to Reduce
+
;; 65. Black Box Testing
(fn get-type
[arg]
(cond
;; :map if you can add a kv pair and pull back out the val with the key
(= 1 (:a (conj arg [:a 1]))) :map
;; :set if adding 2 of the same arg has the same count as adding 1
(= (count (conj arg :a)) (count (conj arg :a :a))) :set
;; :vector if conj adds to front in order
(= '(1 2) (take 2 (conj arg 1 2))) :vector
;; :list otherwise
:default :list))
;; 66. Greatest Common Divisor
(fn gcd
[& vs]
(loop [div (apply min vs)]
(if (every? false? (map #(ratio? (/ % div)) vs))
div
(recur (dec div)))))
;; 67. Prime Numbers
;; Sorry for ugliness, I combined 2 functions into 1 ¯\_(ツ)_/¯
(defn get-primes
([n] (get-primes (sorted-set 2) (dec n)))
([primes n]
(if (= 0 n)
(reverse (into (list) primes))
(recur (conj primes ((fn next-prime
[primes]
(loop [next (inc (last primes))]
(if (every? ratio? (map (partial / next) primes))
next
(recur (inc next))))) primes)) (dec n)))))
;; 68. Recurring Theme
(list 7 6 5 4 3)
;; 69. Merge with a Function
(fn my-merge-with
[f & ms]
(->> ms
(map seq)
(reduce concat)
(group-by first)
(map (fn [[k [first & rest]]] (hash-map k (reduce #(f %1 (second %2)) (second first) rest))))
(apply merge)
(into (sorted-map))))
;; 70. Word Sorting
(fn sort-sentence
[sentence]
(sort-by clojure.string/lower-case (clojure.string/split sentence #"\W")))
;; 71. Rearranging Code: ->
last
;; 72. Rearranging Code: ->>
reduce +
;; 73. Analyze a Tic-Tac-Toe Board
(fn tic-tac-toe
[board]
(letfn
[(three-in-a-row
[[first :as row]]
(if (and (not= :e first) (every? #{first} row)) first))
(horizontal [n] (get board n))
(horizontals [] (map horizontal (range 3)))
(vertical [n] (map #(get % n) board))
(verticals [] (map vertical (range 3)))
(diagonals []
[(map #(get-in %1 [%2 %2]) (repeat board) (range 3))
(map #(get-in %1 [%2 %3]) (repeat board) (range 3) (range 2 -1 -1))])]
(some identity (map three-in-a-row (concat (horizontals) (verticals) (diagonals))))))
;; 74. Filter Perfect Squares
(fn square-filter
[s]
(->> (clojure.string/split s #",")
(map #(Integer/parseInt %))
(filter #(integer? (rationalize (Math/sqrt %))))
(clojure.string/join ",")))
;; 75. Euler's Totient Function
(defn totient
[n]
(letfn [(gcd
[& vs]
(loop [div (apply min vs)]
(if (every? false? (map #(ratio? (/ % div)) vs))
div
(recur (dec div)))))
(coprime?
[n1 n2]
(= (gcd n1 n2) 1))]
(if (not= 1 n)
(count (filter #(coprime? n %) (range 1 n)))
1)))
;; 76. Intro to Trampoline
[1 3 5 7 9 11]
;; 77. Anagram Finder
(fn [s] (into #{} (filter #(> (count %1) 1) (map (comp set second) (group-by frequencies s)))))
;; 78. Reimplement Trampoline
(fn my-trampoline
[f & args]
(loop [val (apply f args)]
(if (fn? val) (recur (val)) val)))
;; 79. Triangle Minimal Path
(fn triangle-path
[tri]
(let [tri (vec tri)]
(loop [score-tri [(first tri)]
depth 1]
(if (< depth (count tri))
(recur
(conj
score-tri
(vec
(map-indexed
#(cond
(zero? %1) (+ %2 (first (get score-tri (dec depth))))
(= %1 depth) (+ %2 (peek (get score-tri (dec depth))))
:else (+ %2 (min (get-in score-tri [(dec depth) (dec %1)])
(get-in score-tri [(dec depth) %1]))))
(get tri depth))))
(inc depth))
(apply min (peek score-tri))))))
;; 80. Perfect Numbers
(fn perfect?
[n]
(letfn [(factor [x] (filter #(zero? (mod x %)) (range 1 (inc (/ x 2)))))]
(= (apply + (factor n)) n)))
;; 81. Set Intersection
#(clojure.set/difference %1 (clojure.set/difference %1 %2))
;; 82. Word Chains
(fn word-chain?
([ws]
(true? (some true? (for [wd ws] (word-chain? (disj ws wd) wd)))))
([ws wd]
(if (empty? ws)
true
(letfn [(insertion? [w1 w2]
(loop [s1 (vec w1)
s2 (vec w2)
insert false]
(if (empty? s1)
true
(if (= (peek s1) (peek s2))
(recur (pop s1) (pop s2) insert)
(if-not insert
(recur s1 (pop s2) true)
false)))))
(substitution? [w1 w2]
(= 1 (count (filter #(apply not= %) (map vector w1 w2)))))
(valid-trans? [w1 w2]
(case (- (count w1) (count w2))
1 ;; w1 is a character longer than w2, may be deletion
(insertion? w2 w1)
-1 ;; w2 is a character longer than w1, may be insertion
(insertion? w1 w2)
0 ;; w1 and w2 are the same, may be substitution
(substitution? w1 w2)
false ;; Not allowed
))]
(some true? (for [wd2 ws] (and (valid-trans? wd wd2) (word-chain? (disj ws wd2) wd2))))))))
;; 83. A Half-Truth
(fn [& v] (not (or (every? true? v) (every? false? v))))
;; 85. Power Set
(fn power-set
[s]
(reduce #(into %1 (for [ss %1] (conj ss %2))) #{#{}} s))
;; 86. Happy Numbers
(fn happy?
([num] (happy? num #{}))
([num seen]
(if (get seen num)
false
(let [sum (apply + (map #(* (Integer/parseInt (str %1)) (Integer/parseInt (str %1))) (str num)))]
(if (= num sum)
true
(recur sum (conj seen num)))))))
;; 88. Symmetric Difference
#(clojure.set/union (clojure.set/difference %1 %2) (clojure.set/difference %2 %1))
;; 90. Cartesian Product
#(set (for [e1 %1 e2 %2] [e1 e2]))
;; 92. Read Roman numerals
(fn parse-rn
[s]
(let [val-map {\I 1
\V 5
\X 10
\L 50
\C 100
\D 500
\M 1000}]
(loop [count 0
string (reverse s)
largest \I]
(cond
(empty? string) count
:default (recur (if (> (get val-map largest)
(get val-map (peek string)))
(- count (get val-map (peek string)))
(+ count (get val-map (peek string))))
(pop string)
(if (> (get val-map largest)
(get val-map (peek string)))
largest
(peek string)))))))
;; 95. To Tree, or not to Tree
(fn binary-tree?
[tree]
(cond
(nil? tree) true
(or (not (coll? tree)) (not= 3 (count tree))) false
(first tree) (every? true? (map binary-tree? (rest tree)))
:else false))
;; 96. Beauty is Symmetry
(fn symmetric-binary-tree?
[tree]
(letfn
[(mirror [tree]
(if (coll? tree)
(concat (list (first tree)) (reverse (map mirror (rest tree))))
tree))
(binary-tree?
[tree]
(cond
(nil? tree) true
(or (not (coll? tree)) (not= 3 (count tree))) false
(first tree) (every? true? (map binary-tree? (rest tree)))
:else false))]
(and (binary-tree? tree) (= tree (mirror tree)))))
;; 97. Pascal's Triangle
(fn pascal
[n]
(letfn [(next-col [i prev]
(if (and (> i 0) (< i (count prev)))
(+ (prev (dec i)) (prev i))
1))
(next-row [prev]
(vec (map next-col (range (inc (count prev))) (repeat prev))))]
(loop [row [1]
n (dec n)]
(if (>= 0 n)
row
(recur (next-row row) (dec n))))))
;; 98. Equivalence Classes
#(set (map set (vals (group-by %1 %2))))
;; 99. Product Digits
(fn [a b] (map #(Integer/parseInt (str %)) (seq (str (* a b)))))
;; 100. Least Common Multiple
(defn lcm
[& ns]
(reduce (fn [n1 n2]
(loop [a n1
b n2]
(cond
(= a b) a
(< a b) (recur (+ a n1) b)
(> a b) (recur a (+ b n2)))))
ns))
;; 101. Levenshtein Distance
(fn levenshtein
[w1 w2]
(loop [i 1
table [(vec (range (inc (count w1))))]]
(if (= i (inc (count w2)))
(last (last table))
(recur (inc i)
(conj table (vec
(loop [j 1
row [i]]
(let [t (conj table row)]
(if (= j (inc (count w1)))
row
(recur (inc j)
(conj row (min (inc (get-in t [(dec i) j]))
(inc (get-in t [i (dec j)]))
(+ (get-in t [(dec i) (dec j)])
(if (= (get w1 (dec j))
(get w2 (dec i)))
0
1))))))))))))))
;; 102. intoCamelCase
(fn into-camel-case
[w]
(reduce #(cond
(= (second %2) \-) %1
(= (first %2) \-) (str %1 (clojure.string/upper-case (str (second %2))))
:default (str %1 (second %2)))
(str (first w))
(map vector w (rest w))))
;; 103. Generating k-combinations
(fn k-combs
[k S]
(cond
(> k (count S)) #{}
(= k (count S)) #{S}
(= k 1) (set (map #(set [%1]) S))
:default
(into #{} (for [e S
S-prime (k-combs (dec k) (clojure.set/difference S #{e}))]
(conj S-prime e)))))
;; 106. Number Maze
(fn number-maze
[start end]
(loop [Q (-> (clojure.lang.PersistentQueue/EMPTY) (conj [start 1]))]
(let [[curr-n steps] (peek Q)]
(if (= end curr-n) steps
(recur (-> (pop Q)
(conj [(* 2 curr-n) (inc steps)]
[(+ 2 curr-n) (inc steps)])
(as-> $ (if (even? curr-n)
(conj $ [(/ curr-n 2) (inc steps)])
$))))))))
;; 108. Lazy Searching
(fn lazy-search
[& ss]
(loop [ss ss]
(letfn [(same-first? [s] (= (first s) (apply min (map first ss))))]
(if (every? same-first? ss)
(ffirst ss)
(recur (map #(if (same-first? %) (rest %) %) ss))))))
;; 110. Sequence of pronounciations
(fn [s]
(letfn [(pronounce [s]
(flatten (map
#(list (count %) (first %))
(partition-by identity s))))]
(rest (iterate pronounce s))))
;; 111. Crossword puzzle
(fn crossword [word board]
(letfn [(fits? [word prompt]
(and
(= (count word) (count prompt))
(every? true? (map #(or (= %1 %2) (= %2 \_)) word prompt))))
(horizontal-prompts [board]
(flatten (map #(clojure.string/split (clojure.string/replace % #" " "") #"#") board)))
(rotate-board [board]
(take-nth 2 (apply map str board)))
(vertical-prompts [board]
(horizontal-prompts (rotate-board board)))]
(or (some #(fits? word %) (concat (horizontal-prompts board) (vertical-prompts board))) false)))
;; 113. Making Data Dance
(fn [& is] (reify
Object (toString [_] (clojure.string/join ", " (sort is)))
clojure.lang.Seqable (seq [_] (if (empty? is) nil (distinct is))))) ;; nil ~= '() in clojure ig
;; 114. Global take-while
(fn taken-while [n p s]
(cond
(empty? s) '()
((comp not p) (first s)) (seq (cons (first s) (taken-while n p (rest s))))
((comp not zero?) (dec n)) (seq (cons (first s) (taken-while (dec n) p (rest s))))
:else '()))
;; 115. The Balance of N
(fn balanced [n]
(let [s (seq (str n))
[h1 h2] (split-at (/ (count s) 2) s)]
(zero? (reduce + (map #(- (Integer/parseInt (str %1)) (Integer/parseInt (str %2)))
h1 h2)))))
;; 158. Decurry
(fn decurry
[curried]
(letfn [(inner [f & args]
(if (empty? args)
f
(apply inner (f (first args)) (rest args))))]
(partial inner curried)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment