This is my first attempt with a lisp language. I'd like your review to address the following points, already listed in order of relevance:
- Is my code making good use of standard library?
- Is my code using the right data structures?
- Is my code well formated and organized?
- Is my code computationally efficient?
Code:
(ns clojure-first-try.core)
(use '[clojure.string :only [split]])
(use '[clojure.set :only [intersection]])
(defn sum [arr]
(reduce + 0.0 arr))
(defn squares [arr]
(map #(* % %) arr))
(defn words-frequency [text]
(as-> text $
(split $ #"\s+")
(filter (complement empty?) $)
(frequencies $)))
(defn cos-numerator [map-1 map-2]
(def common-keys (intersection (set (keys map-1)) (set (keys map-2))))
(sum (map #(* (map-1 %) (map-2 %)) common-keys)))
(defn cos-denominator [map-1 map-2]
(def p-1 (sum (squares (vals map-1))))
(def p-2 (sum (squares (vals map-2))))
(* (Math/sqrt p-1) (Math/sqrt p-2)))
(defn cos-similarity [freq-1 freq-2]
(def a (cos-numerator freq-1 freq-2))
(def b (cos-denominator freq-1 freq-2))
(if (= b 0.0) 0.0 (/ a b)))
(defn sort-by-similarity [base options]
(def base-freq (words-frequency base))
(def sorter (comp (partial cos-similarity base-freq) words-frequency))
(sort-by sorter > options))
Tests:
(ns clojure-first-try.core-test
(:require [clojure.test :refer :all]
[clojure-first-try.core :refer :all]))
(defn close-enough? [a b]
(def delta (- a b))
(def abs-delta (max delta (- delta)))
(> 0.0001 abs-delta))
(deftest words-frequency-test
(testing "Counting the frequency of words in a text with actual words"
(def expected {"a" 3, "bb" 2, "ccc" 4})
(def input "ccc ccc a bb a bb a ccc ccc")
(def result (words-frequency input))
(is (= expected result)))
(testing "Counting the frequency of words in an empty text"
(def expected {})
(def input "")
(def result (words-frequency input))
(is (= expected result))))
(deftest cos-similarity-test
(testing "Getting the similarity of two equal texts"
(def expected 1.0)
(def input-1 {:a 1 :b 2})
(def input-2 {:b 2 :a 1})
(def result (cos-similarity input-1 input-2))
(is (close-enough? expected result)))
(testing "Getting the similarity of two totally different texts"
(def expected 0.0)
(def input-1 {:a 1 :b 2})
(def input-2 {:c 2 :d 1})
(def result (cos-similarity input-1 input-2))
(is (close-enough? expected result)))
(testing "Getting the similarity of two half equal texts"
(def expected 0.5)
(def input-1 {:a 2 :b 2})
(def input-2 {:b 2 :d 2})
(def result (cos-similarity input-1 input-2))
(is (close-enough? expected result))))
(deftest sort-by-similarity-test
(testing "Sorting regular texts"
(def expected ["a b c" "a b d" "d e f"])
(def input-1 "a b c")
(def input-2 ["d e f" "a b c" "a b d"])
(def result (sort-by-similarity input-1 input-2))
(is (= expected result)))
(testing "Sorting empty list of options")
(def expected [])
(def input-1 "a b c")
(def input-2 [])
(def result (sort-by-similarity input-1 input-2))
(is (= expected result)))
All tests passing:
lein test clojure-first-try.core-test
Ran 3 tests containing 7 assertions.
0 failures, 0 errors.