Empty Maps in Clojure

2019-09-23 01:48发布

问题:

I keep getting empty maps when i am passing data into two hash maps in clojure, i know that the data is being sent through the functions as i have used print statements that show it correct data, its just when i assoc the data to the map it doesnt appear to do anything and leaves me with {}

Can anyone see what i am doing wrong??

(defn sort-string [y]
  (apply str (sort y)))

(defn get-unique [y]
  (let [x (sort-string (str/lower-case y))
        hashmap1 (hash-map)
        hashmap2 (hash-map)]

    (if-not (contains? hashmap1 x)
      (assoc hashmap1 x, y)
      (assoc hashmap2 y, y))

    (if-not (get hashmap1 x) y)
    (dissoc hashmap2 (get hashmap1 x))))

(for [strings '("door" " rood" "pen" "open" "high" "low" "wall" "lawl" "#")]
  (get-unique strings))

回答1:

Clojure maps are immutable. So the assocs, which return modified maps, have no effect, as the returned values are not used.

I don't know what you're trying to do, but the following might get you on the right lines:

(defn get-unique [y]
  (let [x (sort-string (str/lower-case y))
        hashmap1 (hash-map)
        hashmap2 (hash-map)
        [hashmap1 hashmap2]  (if-not (contains? hashmap1 x)
                               [(assoc hashmap1 x, y) (assoc hashmap2 y, y)]
                               [hashmap1 hashmap2])]

    (if-not (= (get hashmap1 x) y)
      (dissoc hashmap2 (get hashmap1 x))
      hashmap2)))

For example,

(for [strings '("door" " rood" "pen" "open" "high" "low" "wall" "lawl" "#")]
  (get-unique strings))

;({"door" "door"} {" rood" " rood"} {"pen" "pen"} {"open" "open"} {"high" "high"} {"low" "low"} {"wall" "wall"} {"lawl" "lawl"} {"#" "#"})

Now that your comment tells me you are trying to group anagrams together, using sort-string to test for equivalences ...

You can do this using group-by. For example,

(let [strings '("door" " rood" "pen" "open" "high" "low" "wall" "lawl" "#")]
  (group-by sort-string strings))

... produces ...

{"door" ["door" "rood"], "enp" ["pen"], "enop" ["open"], "ghhi" ["high"], "low" ["low"], "allw" ["wall" "lawl"], "#" ["#"]}


回答2:

I think the mistake you're making is assuming hashmap1 and hashmap2 are mutable. assoc returns a new hashmap with the associated key and value, but the original remains unchanged.

You can see this in a repl like so:

user=> (def my-map {:a 1 :b 2})
#'user/my-map
user=> my-map
{:a 1, :b 2}
user=> (assoc my-map :c 3)
{:a 1, :b 2, :c 3}
user=> my-map
{:a 1, :b 2}

This means your block:

(if-not (contains? hashmap1 x)
  (assoc hashmap1 x, y)
  (assoc hashmap2 y, y))

just created a new hashmap with x as a key and y as a value and threw didn't do anything with it.

Maybe you could write another function to create the new map and return it like so:

(defn add-if-not-contains [m1 m2 x y]
    (if-not (contains? m1 x)
        [(assoc m1 x y) m2]
        [m1 (assoc m2 y y)]))

But your solution is still overly complicated I think. I'm guessing you want a single sorted element that does not have any other permutations in the list.

user=> (def my-strings ["door" " rood" "pen" "open" "high" "low" "wall" "lawl" "#"])
#'user/my-string

user=> (distinct (map sort-string my-strings))      
("door" " door" "enp" "enop" "ghhi" "low" "allw" "#")

If you want to just get words that have no permutation, you might try something like this

(frequencies (map sort-string ["door" "rood" "odor" "pen"]))
{"door" 3, "enp" 1}

Filtering that result to find entries with a value of 1 and finding the original word from the permutation are left as an exercise.