Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to do group-by and count at once in Clojure?

Tags:

clojure

Assume that there is a sequence like below:

["ab" "ba" "ac" "ca" "bc" "cc"]

I want to know the frequencies but the key should be sorted string. In short, I want to get the result like this:

{"ab" 2, "ac" 2, "bc" 1, "cc" 1}

Clojure has frequencies function, but it doesn't accept key function. So, usually I can do this by the combination of group-by and map:

(->> ["ab" "ba" "ac" "ca" "bc" "cc"]
     (group-by #(apply str (sort %)))
     (map (fn [[k vs]] [k (count vs)]))
     (int {}))

But, this looks verbose. Even in Java, I can do grouping and counting at the same time with Stream API, like this: (Assuming that there is a method sortedStr(s)

Arrays.asList("aa", "ab", "ab", "bb", "cc" , "ca")
  .stream()
  .collect(groupingBy(s->sortedStr(s), counting()));

Is there any way to group-by and counting at once in clojure like Java8?

like image 533
ntalbs Avatar asked Aug 10 '16 22:08

ntalbs


Video Answer


2 Answers

Here is a Clojure version using the built-in frequencies function.

 (frequencies (map #(apply str (sort %)) 
                   ["ab" "ba" "ac" "ca" "bc" "cc"]))
 ;;=> {"ab" 2, "ac" 2, "bc" 1, "cc" 1}

I may be wrong, but the Java version already gets the sorted keys in your example. In that case, it would be just a call to frequencies in Clojure (if I understood your question correctly).

EDIT: Looks like the Java version was corrected in the meantime, so my last comment becomes obsolete.

like image 52
Stefan Kamphausen Avatar answered Sep 22 '22 22:09

Stefan Kamphausen


@Stefan answer works well, but it is not the most efficient, because it first maps over the coll (producing an intermediate collection) and then finds frequencies. So it doesn't really conform to "group-by and count at once" part of your question. I would rather go with reduce:

user> (reduce #(update %1 (apply str (sort %2)) (fnil inc 0))
              {} ["ab" "ba" "ac" "ca" "bc" "cc"])
{"ab" 2, "ac" 2, "bc" 1, "cc" 1}
like image 38
leetwinski Avatar answered Sep 19 '22 22:09

leetwinski