Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Week 1 #1

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
50 changes: 50 additions & 0 deletions src/new_hope/diagonal_difference.clj
Original file line number Diff line number Diff line change
@@ -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]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can do instead

(defn diagonal1 [n]
  (for [i (range n)]
    [i i]))
(defn diagonal2 [n]
  (for [i (range n)]
    [i (- (dec n) i)]))
(facts "about diagonals"
  (diagonal1 3) => [[0 0] [1 1] [2 2]]
  (diagonal2 3) => [[0 2] [1 1] [2 0]])

and then define a generic function that sums all elements by their positions

(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)))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any sense in this, almost no typing saved and no additional abstraction introduced.


(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)
28 changes: 28 additions & 0 deletions src/new_hope/fizz_buzz.clj
Original file line number Diff line number Diff line change
@@ -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]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to generalize for an arbitrary config, so that the following works:

(map (partial fizz-buzz [3 "Fizz" 5 "Buzz"]) (range 1 31))

(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"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be more nice to have all "fizz" cases under one facts. Same for "buzz"

(fizz? 4) => false)

(facts "buzz is working"
(buzz? 10) => true)

(facts "buzz is working"
(buzz? 12) => false)
49 changes: 49 additions & 0 deletions src/new_hope/insertionsort1.clj
Original file line number Diff line number Diff line change
@@ -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]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really hairy, sorry :) And also does not work with lists: (insert-elem '(5 6 9 7))
I think that insertion sort could traverse the input once and build a list as a result, it supports insertions in a more natural way than any other data structure.

(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]
)
50 changes: 50 additions & 0 deletions src/new_hope/insertionsort2.clj
Original file line number Diff line number Diff line change
@@ -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])
20 changes: 20 additions & 0 deletions src/new_hope/predicate_validators.clj
Original file line number Diff line number Diff line change
@@ -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)))
50 changes: 50 additions & 0 deletions src/new_hope/runningtime.clj
Original file line number Diff line number Diff line change
@@ -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])
113 changes: 113 additions & 0 deletions src/new_hope/week1.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, a simpler solution exists, it's enough to compare the original sequence to its reversed version

(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]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flatten works on all levels,

(dupl [[1][2]]) => [1 1 2 2] ;; instead of [[1] [1] [2] [2]]

(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])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use comment block to prevent evaluation when the source file is loaded.


;; Day 5

(defn compress [col]
(if (empty? col)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is excessive. Try to design the termination check inside loop so that it catches empty input as well.

col
(loop [elem (first col)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest renaming elem -> prev-elem to incease readability

rest-col (rest col)
result []]
(if (empty? rest-col)
(conj result elem)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this conj be avoided? We already have conj call below, there should be only one enough

(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))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should check indexes, not values. This will fail:
(drop-nth [:a :b :c :d :e :f :g] 3)


(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))))
Expand Down
Loading