diff --git a/README.md b/README.md index 4dfb7fd..b99c7a9 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ This is a pre-configured project that you can use to do exercises from the book: [Living Clojure](http://shop.oreilly.com/product/0636920034292.do) by Carin Meier +Exercises are given in a weekly plan in Chapter 10. + ## Prerequisites diff --git a/src/new_hope/diagonal_difference.clj b/src/new_hope/diagonal_difference.clj new file mode 100644 index 0000000..440b9a3 --- /dev/null +++ b/src/new_hope/diagonal_difference.clj @@ -0,0 +1,50 @@ +(ns new-hope.diagonal-difference + (:require [midje.sweet :refer :all] + [criterium.core :as crit])) + +;https://www.hackerrank.com/challenges/diagonal-difference + +(def matrix [[11 2 4] [4 5 6] [10 8 -12]]) + +(defn element [m i j] (nth (nth m i) j)) + +(defn first-sum [m, n] + (loop [sum 0 + line 0] + (if (= n line) + sum + (recur (+ sum (element m line line)) (inc line))))) + +(defn second-sum [m n] + (loop [sum 0 + line 0] + (if (= n line) + sum + (recur (+ sum (element m line (- n (+ line 1)))) (inc line))))) + +(defn abs-of-diff [x y] (Math/abs (- x y))) + +(defn diff-of-diags [m n] + (abs-of-diff (first-sum m n) (second-sum m n))) + +(facts "diff of diags" + (diff-of-diags matrix 3) => 15) + +(facts "should diff" + (abs-of-diff 9 1) => 8 + (abs-of-diff -9 1) => 10 + (abs-of-diff 9 10) => 1) + +(facts "first sum" + (first-sum matrix 3) => 4) + +(facts "second sum" + (second-sum matrix 3) => 19) + + + +(facts "write element" + (element matrix 1 1) => 5 + (element matrix 0 0) => 11 + (element matrix 0 2) => 4 + (element matrix 2 1) => 8) \ No newline at end of file diff --git a/src/new_hope/fizz_buzz.clj b/src/new_hope/fizz_buzz.clj new file mode 100644 index 0000000..a32ceb5 --- /dev/null +++ b/src/new_hope/fizz_buzz.clj @@ -0,0 +1,28 @@ +(ns new-hope.fizz-buzz + (:require [midje.sweet :refer :all])) + +(def fizz? #(= (mod % 3) 0)) + +(def buzz? #(= (mod % 5) 0)) + +(defn fizz-buzz [n] + (if (and (fizz? n) (buzz? n)) + "FizzBuzz" + (cond (fizz? n) "Fizz" + (buzz? n) "Buzz" + :else (str n)))) + +(map fizz-buzz (range 1 31)) + + +(facts "fizz is working" + (fizz? 3) => true) + +(facts "fizz is working" + (fizz? 4) => false) + +(facts "buzz is working" + (buzz? 10) => true) + +(facts "buzz is working" + (buzz? 12) => false) \ No newline at end of file diff --git a/src/new_hope/insertionsort1.clj b/src/new_hope/insertionsort1.clj new file mode 100644 index 0000000..78f182b --- /dev/null +++ b/src/new_hope/insertionsort1.clj @@ -0,0 +1,49 @@ +(ns new-hope.insertionsort1 + (:require [midje.sweet :refer :all])) + +; https://www.hackerrank.com/challenges/insertionsort1 + +(def arr [2 4 6 8 3]) + +(def arr-size (count arr)) +(def elem (last arr)) + + +(defn insert-elem [arr] + (if (< (count arr) 2) + (do (apply println arr) + arr) + (let [elem-to-insert (last arr)] + (loop [index (dec (count arr)) + prev-index (dec index) + arr arr] + (if (< prev-index 0) + (let [new-arr (assoc arr index elem-to-insert)] + (apply println new-arr) + new-arr) + (if (> (nth arr prev-index) elem-to-insert) + (let [new-arr (assoc arr index (nth arr prev-index))] + (apply println new-arr) + (recur (dec index) (dec prev-index) new-arr)) + (let [new-arr (assoc arr index elem-to-insert)] + (apply println new-arr) + new-arr) + )))))) + + + +(fact "the size is correct" + arr-size => 5) + +(fact "elem is the correct one" + elem => 3) + +(fact "insert works" + (insert-elem []) => [] + (insert-elem [3]) => [3] + (insert-elem [1 3]) => [1 3] + (insert-elem [1 2 3]) => [1 2 3] + (insert-elem [5 3]) => [3 5] + (insert-elem [5 6 9 7]) => [5 6 7 9] + (insert-elem arr) => [2 3 4 6 8] + ) \ No newline at end of file diff --git a/src/new_hope/insertionsort2.clj b/src/new_hope/insertionsort2.clj new file mode 100644 index 0000000..5739044 --- /dev/null +++ b/src/new_hope/insertionsort2.clj @@ -0,0 +1,50 @@ +(ns new-hope.insertionsort2 + (:require [midje.sweet :refer :all])) + +; https://www.hackerrank.com/challenges/insertionsort2 + +(def arr [1 4 3 5 6 2]) + + +(defn insert-elem [arr size] + (if (< size 2) + arr + (let [elem-to-insert (nth arr (dec size))] + (loop [index (dec size) + prev-index (dec index) + arr arr] + (if (< prev-index 0) + (let [new-arr (assoc arr index elem-to-insert)] + new-arr) + (if (> (nth arr prev-index) elem-to-insert) + (let [new-arr (assoc arr index (nth arr prev-index))] + (recur (dec index) (dec prev-index) new-arr)) + (let [new-arr (assoc arr index elem-to-insert)] + new-arr) + )))))) + +(defn insert-sort [arr] + (loop [arr arr + size 2] + (if (< (count arr) size) + arr + (let [new-arr (insert-elem arr size)] + (do + (apply println new-arr) + (recur new-arr (inc size))))))) + +(fact "insert works" + (insert-elem [] 0) => [] + (insert-elem [3] 1) => [3] + (insert-elem [1 3] 2) => [1 3] + (insert-elem [1 2 3] 3) => [1 2 3] + (insert-elem [5 3] 2) => [3 5] + (insert-elem [5 6 9 7] 4) => [5 6 7 9] + (insert-elem [5 6 2 1] 3) => [2 5 6 1] + ) + +(fact "sort works" + (insert-sort arr) => [1 2 3 4 5 6] + (insert-sort [1]) => [1] + (insert-sort []) => [] + (insert-sort [2 1]) => [1 2]) \ No newline at end of file diff --git a/src/new_hope/predicate_validators.clj b/src/new_hope/predicate_validators.clj new file mode 100644 index 0000000..cf5cdcb --- /dev/null +++ b/src/new_hope/predicate_validators.clj @@ -0,0 +1,20 @@ +(ns new-hope.predicate-validators + (require :require [midje.sweet :refer :all])) + +(defmulti validate-predicate + "Validates a predicate and returns a list of validation errors" + :name) + +(defmethod validate-predicate "path" [predicate] + (let [validation-errors (transient []) + args-size (count (predicate :args))] + (if (not= 1 args-size) + (conj! validation-errors "Wrong number of arguments")) + (persistent! validation-errors))) + +(defmethod validate-predicate "header" [predicate] + (let [validation-errors (transient []) + args-size (count (predicate :args))] + (if (not= 2 args-size) + (conj! validation-errors "Wrong number of arguments")) + (persistent! validation-errors))) diff --git a/src/new_hope/runningtime.clj b/src/new_hope/runningtime.clj new file mode 100644 index 0000000..5739044 --- /dev/null +++ b/src/new_hope/runningtime.clj @@ -0,0 +1,50 @@ +(ns new-hope.insertionsort2 + (:require [midje.sweet :refer :all])) + +; https://www.hackerrank.com/challenges/insertionsort2 + +(def arr [1 4 3 5 6 2]) + + +(defn insert-elem [arr size] + (if (< size 2) + arr + (let [elem-to-insert (nth arr (dec size))] + (loop [index (dec size) + prev-index (dec index) + arr arr] + (if (< prev-index 0) + (let [new-arr (assoc arr index elem-to-insert)] + new-arr) + (if (> (nth arr prev-index) elem-to-insert) + (let [new-arr (assoc arr index (nth arr prev-index))] + (recur (dec index) (dec prev-index) new-arr)) + (let [new-arr (assoc arr index elem-to-insert)] + new-arr) + )))))) + +(defn insert-sort [arr] + (loop [arr arr + size 2] + (if (< (count arr) size) + arr + (let [new-arr (insert-elem arr size)] + (do + (apply println new-arr) + (recur new-arr (inc size))))))) + +(fact "insert works" + (insert-elem [] 0) => [] + (insert-elem [3] 1) => [3] + (insert-elem [1 3] 2) => [1 3] + (insert-elem [1 2 3] 3) => [1 2 3] + (insert-elem [5 3] 2) => [3 5] + (insert-elem [5 6 9 7] 4) => [5 6 7 9] + (insert-elem [5 6 2 1] 3) => [2 5 6 1] + ) + +(fact "sort works" + (insert-sort arr) => [1 2 3 4 5 6] + (insert-sort [1]) => [1] + (insert-sort []) => [] + (insert-sort [2 1]) => [1 2]) \ No newline at end of file diff --git a/src/new_hope/week1.clj b/src/new_hope/week1.clj index 917e564..28b0815 100644 --- a/src/new_hope/week1.clj +++ b/src/new_hope/week1.clj @@ -21,8 +21,121 @@ (facts "some facts" (second [2 3 4]) => 3) + +;; Day 3 + +(re-seq #"jam" "I like jam in my jam") + +(apply str [1 2 3]) + +(apply str (re-seq #"A-Z+" "AadfBdfasZaa")) + +(.toUpperCase (str (first [:cat :dog :fish]))) + +(-> [:cat :dog :fish] + first + str + .toUpperCase) + +(->> [1 2 3 4 5 6 7 8] + (filter odd?) + (take 2)) + +(for [x (range 40) + :when (= 1 (rem x 4))] + x) + +(for [x (iterate #(+ 4 %) 0) + :let [z (inc x)] + :while (< z 40)] + x) + +(for [[x y] (partition 2 (range 20))] + [x y]) + ;; Day 4 +(defn second-to-last [col] + (if (< (count col) 2) + nil + (nth col (- (count col) 2)))) + +(facts "should return the second to last" + (second-to-last (list 1 2 3 4 5)) => 4 + (second-to-last ["a" "b" "c"]) => "b" + (second-to-last [[1 2] [2 3]]) => [1 2] + (second-to-last []) => nil + (second-to-last [1]) => nil) + +(defn sum [col] + (reduce + col)) + +(facts "should return the sum" + (sum [1 2 3]) => 6) + +(defn odd-numbers [col] + (filter odd? col)) + +(facts "should return the odd numbers" + (odd-numbers #{1 2 3 4 5}) => '(1 3 5)) + +(defn palindrome [col] + (let [size (count col) + half-count (quot size 2) + nr-of-dropped (if (even? size) half-count (inc half-count)) + first-half (take half-count col) + second-half (drop nr-of-dropped col)] + (= first-half (reverse second-half)))) + +(facts "should return true for palindrome" + (palindrome "racecar") => true + (palindrome [1 2 3 4 5]) => false + (palindrome [1 2 3 2 1]) => true) + +(defn dupl [col] + (flatten (map (fn [x] [x x]) col))) + +(facts "should duplicate elements" + (dupl [1 2 3]) => '(1 1 2 2 3 3)) + +(palindrome [1 2 4 5]) + +;; Day 5 + +(defn compress [col] + (if (empty? col) + col + (loop [elem (first col) + rest-col (rest col) + result []] + (if (empty? rest-col) + (conj result elem) + (let [new-elem (first rest-col) + new-result (if (= elem new-elem) + result + (conj result elem))] + (recur new-elem (rest rest-col) new-result)))))) + +(facts "should compress a seq" + (compress [1]) => [1] + (compress []) => [] + (compress [1 1 2 2 3 3 3 4 4 5 3]) => [1 2 3 4 5 3]) + +(defn drop-nth [col n] + (filter #(not= 0 (rem % n)) col)) + +(facts "should drop every nth element" + (drop-nth [1 2 3 4 5 6 7 8] 3) => [1 2 4 5 7 8]) + + +(take 5 (iterate inc 1)) + +(defn replic [col n] + (flatten (map #(take n (iterate identity %)) col))) + +(facts "should replace each element a number of times" + (replic [1 2 3] 2) => [1 1 2 2 3 3]) + (def second-to-last (fn [coll] (second (reverse coll)))) diff --git a/src/new_hope/week2.clj b/src/new_hope/week2.clj new file mode 100644 index 0000000..a4170f7 --- /dev/null +++ b/src/new_hope/week2.clj @@ -0,0 +1,100 @@ +(ns new-hope.week1 + (:require [midje.sweet :refer :all] + [criterium.core :as crit])) + + + +(defn filter-caps [s] + (apply str (filter #(Character/isUpperCase %) s))) + +(facts "it should filter the capital letters" + (filter-caps "HeLlO, WoRlD!") => "HLOWRD" + (filter-caps "nothing") => "" + (filter-caps "$#A(*&987Zf") => "AZ") + +(comment + (some #{2 7 6} [5 6 7 8])) + + +(defn factorial + "calculates the factorial of a number" + [n] + (loop [result 1 + index 1] + (if (= index n) + (* result index) + (recur (* result index) (inc index))))) + +(facts "it should calculate factorial" + (factorial 1) => 1 + (factorial 2) => 2 + (factorial 8) => 40320) + +(= [2 4] (let [[a b c d e f g] (range)] [2 4])) + +(= [1 2 [3 4 5] [1 2 3 4 5]] (let [[a b & c :as d] [1 2 3 4 5]] [a b c d])) + +(defn- some-bool [b list] + (true? (some #(= % b) list))) + +(defn the-predicate [& args] + (and (some-bool true args) (some-bool false args))) + +(facts "it should return true or false" + (the-predicate false false) => false + (the-predicate true false) => true + (the-predicate true) => false + (the-predicate false true false) => true + (the-predicate true true true) => false + (the-predicate true true true false) => true) + +(defn gcd [a b] + (if (zero? b) + a + (recur b (mod a b)))) + +(facts "it should calculate the gcd" + (gcd 2 4) => 2 + (gcd 10 5) => 5 + (gcd 5 7) => 1 + (gcd 1023 858) => 33) + +(defn cartesian-product [set-1 set-2] + (set (for [x set-1 + y set-2] + [x y]))) + +(fact "should do the cartesian product" + (cartesian-product #{1 2 3} #{4 5}) => #{[1 4] [2 4] [3 4] [1 5] [2 5] [3 5]}) + +(defn- some-to-bool [pred list] + (true? (some pred list))) + +(defn symmetric-difference [set-1 set-2] + (clojure.set/union + (clojure.set/difference set-1 set-2) + (clojure.set/difference set-2 set-1))) + +(facts "should return the difference" + (symmetric-difference #{1 2 3 4 5 6} #{1 3 5 7}) => #{2 4 6 7}) + +(defn add-adiacent [xs] + (if (= 1 (count xs)) + [] + (map #(apply + %) (partition 2 1 xs)))) + +(facts "is should add adiacent numbers" + (add-adiacent [1 2 3 4]) => [3 5 7] + (add-adiacent [1 1]) => [2] + (add-adiacent [1 3 3 1]) => [4 6 4]) + +(defn pascal [n] + (loop [result [1] + index 1] + (if (= index n) + result + (recur (concat [1] (add-adiacent result) [1]) (inc index))))) + +(facts "should calculate pascal" + (pascal 1) => [1] + (pascal 11) => [1 10 45 120 210 252 210 120 45 10 1]) \ No newline at end of file diff --git a/test/new_hope/predicate_validators_facts.clj b/test/new_hope/predicate_validators_facts.clj new file mode 100644 index 0000000..fe51064 --- /dev/null +++ b/test/new_hope/predicate_validators_facts.clj @@ -0,0 +1,17 @@ +(ns new-hope.predicate-validators-facts + (:require [new-hope.predicate-validators :refer :all] + [midje.sweet :refer :all])) + +(facts "validate the predicates" + (fact "for a valid path predicate" + (let [valid-path-predicate {:name "path" :args ["/hello"]}] + (count (validate-predicate valid-path-predicate))) => 0) + (fact "for an invalid path predicate" + (let [invalid-path-predicate {:name "path" :args ["/hello", "/hello1"]}] + (count (validate-predicate invalid-path-predicate))) => 1) + (fact "for a valid header predicate" + (let [valid-header-predicate {:name "header" :args ["X-Name" "value"]}] + (count (validate-predicate valid-header-predicate))) => 0) + (fact "for an invalid header predicate" + (let [invalid-header-predicate {:name "header" :args ["X-Name"]}] + (count (validate-predicate invalid-header-predicate))) => 1))