Reputation: 99
Ok so put into my function an array an I keep so do some stuff to return a hashmap with a string as key and a list as value. I want to get only the final value and pass it as a parameter to another function.
Below is a java code which i am trying to translate into clojure
contents = documentContent.split("[ ,\\.]+");
for(int i = 0; i < contents.length; i++) {
String word = contents[i];
if(index.containsKey(word)) {
index.get(word).add(i);
} else {
List<Integer> list = new ArrayList<>();
list.add(i);
index.put(word, list);
}
}
Clojure code so far it somewhat works but i cant return the final value and pass it to another function
(defn indexFinder [contents]
(let [mem (def xs (atom {}))]
(map-indexed
(fn [index element]
(if (contains? @xs element)
(swap! xs assoc element (conj (@xs element) index))
(swap! xs assoc element [index])))
contents)))
Upvotes: 0
Views: 210
Reputation: 18005
Here is how I would write it:
(defn index-finder [s]
(->> (clojure.string/split s #"[ ,\\.]+")
(map-indexed list)
(reduce (fn [acc [i w]]
(update acc w conj i)) {})))
Example use:
(index-finder "aaa bbb ccc ddd aaa bbb") ;; {"aaa" (4 0), "bbb" (5 1), "ccc" (2), "ddd" (3)}
Note: when starting learning Clojure, one tends to think that he needs atoms way to often.
Upvotes: 2
Reputation: 1976
The original indexFinder is missing a doall to force its side effects (to update the atom). And also declaration of mem is not required. With that, a working version may look like this:
(defn indexFinder [contents]
(let [xs (atom {})]
(doall (map-indexed
(fn [index element]
(if (contains? @xs element)
(swap! xs assoc element (conj (@xs element) index))
(swap! xs assoc element [index])))
contents))
@xs))
You can also simplify the map-indexed part:
(defn indexFinder [contents]
(let [xs (atom {})]
(doall (map-indexed
(fn [i e] (swap! xs update e conj i))
contents))
@xs))
Or if you don't want to rely on side effects, you can use this instead (similar to Brandon's answer but use group-by):
(defn index-finder [contents]
(->> (zipmap (range) contents)
(group-by last)
(fmap (partial map first))))
where fmap is used to map a function over values (see algo.generic):
(defn fmap [f m]
(into (empty m) (for [[k v] m] [k (f v)])))
Upvotes: 1
Reputation: 3720
I'd recommend against the atom in the first place.
(->> (zipmap (range) contents) ;contents is a list of words
(reduce (fn [index [location word]]
(merge-with concat index {word (list location)})) {}))
example:
user=> (def contents (clojure.string/split "hello there these are some words and some repeated words" #" "))
#'user/contents
user=> contents
["hello" "there" "these" "are" "some" "words" "and" "some" "repeated" "words"]
user=> (->> (zipmap (range) contents)
#_=> (reduce (fn [index [location word]]
#_=> (merge-with concat index {word (list location)})) {}))
{"hello" (0), "some" (7 4), "there" (1), "and" (6), "are" (3), "these" (2), "words" (9 5), "repeated" (8)}
Upvotes: 1