anagram.clj

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(ns anagram
  (:require [clojure
             [string :refer [lower-case]]
             [test :refer [is with-test]]]))

(with-test
  (defn assoc-code-pattern
    "Return amap with the letter as the key and increases the
   number of occurences by 1. For instance, given {:a 3 :e 1},
   passing it with a :e, it returns {:a 3 :e 2}, but passing
   it a :f, it returns {:a 3 :e 2 :f 1}. The keys is supposed
   to be a character."
    [pattern-map letter]
    (assoc pattern-map
           letter
           (inc (get pattern-map letter 0))))

  ;; These test cases serve to illustrate this function's behavior:
  (is (= (assoc-code-pattern {}          \e)  {\e 1}))
  (is (= (assoc-code-pattern {\a 3 \e 1} \e)  {\a 3 \e 2}))
  (is (= (assoc-code-pattern {\a 3 \e 1} \f)  {\a 3 \e 1 \f 1})))

(with-test
  (defn code-pattern
    "Given a string, returns the signature pattern, where each
   letter is a key, and the number of occurances is the value."
    [word]
    (reduce assoc-code-pattern {} (lower-case word)))

  ;; These test cases serve to illustrate this function's behavior:
  (is (= (code-pattern "Beagle") {\b 1, \e 2, \a 1, \g 1, \l 1}))
  (is (= (code-pattern "")       {})))

;; To make the `compare-anagrams' function more effecient, we
;; place a mini-cache in front of this function so if we call
;; the function with the same word, we don't have to
;; recalculate the pattern.

(def code-pattern-m (memoize code-pattern))

(with-test
  (defn compare-anagrams
    "Predicate compares parameters to decide is word1 is an anagram of word2."
    [word1 word2]
    (if (.equalsIgnoreCase word1 word2)
      false
      (= (code-pattern-m word1) (code-pattern-m word2))))

  ;; These test cases serve to illustrate this function's behavior:
  (is      (compare-anagrams "Carthorse" "Orchestra"))
  (is (not (compare-anagrams "Carthorsey" "Orchestra")))
  (is (not (compare-anagrams "Carthorse" "Orchestr")))
  (is (not (compare-anagrams "banana" "banana")))
  (is (not (compare-anagrams "BANANA" "banana"))))

(defn anagrams-for
  "Given a string and a list of words, return words that are anagrams of the first"
  [a-word words]
  (filter #(compare-anagrams a-word %) words))

Comments

These are involved. Are you avoiding certain built-ins for some reason?

wobh commented 21 November 2015 at 07:18 UTC

You're not logged in right now. Please login via GitHub to comment