Skip to content

Instantly share code, notes, and snippets.

@shardnit
Last active August 29, 2015 14:00
Show Gist options
  • Save shardnit/d6f1035eadfb8f73a297 to your computer and use it in GitHub Desktop.
Save shardnit/d6f1035eadfb8f73a297 to your computer and use it in GitHub Desktop.
Clojure practice
; Write a function to find out if a string is a palindrome–that is, if it looks the same forwards and backwards.
(defn palindrome?
[word]
(=
word
(apply str (reverse word))
)
)
;Find the number of ‘c’s in “abracadabra”.
(defn alphabet_count
[alphabet word]
(count
(filter
(fn [x] ( = x alphabet ))
word
)
)
)
(defn alphabet-count [alphabet word]
((frequencies word) alphabet)
)
;Write your own version of filter.
(defn my-filter
[function sequence]
(apply concat
(map
(fn [x] ( if(function x) [x] []))
sequence
)
)
)
;Find the first 100 prime numbers
(defn hundred-primes []
(take 100
(filter
(fn [x]
(not-any?
(fn [y] (= (mod x y) 0))
(range 2 x))
)
(iterate inc 2)
)
)
)
;Macros, control flow, comprehensions
;write a schedule function which, given an hour of the day, returns what you’ll be doing at that time.
;(schedule 18), for me, returns :dinner.
(defn schedule [hour]
(cond
(>= 8 hour) :sleeping
(and (< 8 hour) (>= 9 hour)) :getting-ready
(and (> 9 hour) (>= 10 hour)) :on-my-way-to-work
(and (< 10 hour) (>= 18 hour)) :work
(and (< 18 hour) (>= 20 hour)) :workout
(and (< 20 hour) (>= 22 hour)) :dinner
(and (< 22 hour) (>= 24 hour)) :sleeping
:else :not-a-valid-hour
)
)
(schedule 25)
;find how many numbers from 0 to 9999 are palindromes
(defn reverse-int [number]
(Integer. (apply str(reverse (str number))))
)
(defn find-palindromes [start end]
(->>
(range start end)
(filter
(fn [x]
(= x (reverse-int x))
)
)
)
)
(find-palindromes 0 9999)
;a macro id which takes a function and a list of args: (id f a b c),
;and returns an expression which calls that function with the given args: (f a b c)
(defmacro id [function & arguments]
(cons function arguments)
)
(macroexpand '(id into [] #{:a :b :c}))
(eval (macroexpand '(id into (list) #{:a :b :c})))
;a macro log which uses a var, logging-enabled, to determine whether or not to print an expression to the console at compile time.
;If logging-enabled is false, (log :hi) should macroexpand to nil.
;If logging-enabled is true, (log :hi) should macroexpand to (prn :hi).
(def logging-enabled true)
(defmacro log [message]
(if logging-enabled
`(prn ~message)
)
)
(macroexpand '(log :hi))
(defmacro log [message]
(if logging-enabled
(list 'prn message)
)
)
(macroexpand '(log :hi))
;Clojure state practice
(defn sum [start end]
(reduce +
(range start end)
)
)
(time (sum 0 1e7))
;"Elapsed time: 395.185 msecs"
;49999995000000
(time (def later (delay (sum 0 1e7))))
;"Elapsed time: 0.149 msecs"
;#'user/later
(time (deref later))
;"Elapsed time: 340.081 msecs"
;49999995000000
(time (deref later))
;"Elapsed time: 0.025 msecs"
;49999995000000
(.start (Thread. (fn [] (sum 0 1e7)))
;but this simply runs the (sum) function and discards the results
(def sum-promise(promise))
(.start (Thread. (fn [] (deliver sum-promise (sum 0 1e7)))))
@sum-promise
;Use this technique to write your own version of the future macro????
(let [result1 (future (sum 0 (/ 1e7 2))) result2 (future (sum (/ 1e7 2) 1e7))] (time (+ @result1 @result2)))
;"Elapsed time: 285.546 msecs"
;4.9999995E13
;Instead of using reduce, store the sum in an atom and use two futures to add each number from the lower and upper range to that atom.
;Wait for both futures to complete using deref, then check that the atom contains the right number.
;Is this technique faster or slower than reduce? Why do you think that might be?
(def total_sum (atom 0))
(let [result1 (future (doseq [i (range 0 (/ 1e7 2))] (swap! total_sum + i)))
result2 (future (doseq [i (range (/ 1e7 2) 1e7)] (swap! total_sum + i)))] (time @result1))
; takes more time - may be because of overhead of using atom.
;Write a function which, in a dosync transaction, removes the first number in work and adds it to sum.
;Then, in two futures, call that function over and over again until there’s no work left. Verify that @sum is 4999950000.
;Experiment with different combinations of alter and commute–if both are correct, is one faster?
Does using deref instead of ensure change the result?
(def work (ref (apply list (range 1e5))))
(def sum (ref 0))
(defn remove_and_add [work_pile add_to] (dosync (alter sum + (first (ensure work_pile))) (alter work_pile rest)))
(let [x1 (future (dosync (while (not= (count (ensure work)) 0) (do (remove_and_add work sum)))))
x2 (future (dosync (while (not= (count (ensure work)) 0) (do (remove_and_add work sum)))))]
(time @x1))
;"Elapsed time: 263.02 msecs"
;@sum
;4999950000
(defn remove_and_add [work_pile add_to] (dosync (commute sum + (first (ensure work_pile))) (commute work_pile rest)))
(let [x1 (future (dosync (while (not= (count (ensure work)) 0) (do (remove_and_add work sum)))))
x2 (future (dosync (while (not= (count (ensure work)) 0) (do (remove_and_add work sum)))))]
(time @x1))
;"Elapsed time: 399.703 msecs"
;;@sum
;4999950000
;Surprisingly more time with commute?!!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment