Is there a scala / java equivalent of Python 3.Counter collections

I need a class that will count the number of objects that I have - it sounds more efficient than collecting all the objects and then grouping them.

Python has a perfect structure in collections.Counter , does Java or Scala have a similar type?

+6
source share
7 answers

From the documentation you linked:

The Counter class is similar to bags or multisets in other languages.

Java does not have a Multiset class or equivalent. Guava has a Multiset collection that does exactly what you want.

In pure Java, you can use Map<T, Integer> and the new merge method:

 final Map<String, Integer> counts = new HashMap<>(); counts.merge("Test", 1, Integer::sum); counts.merge("Test", 1, Integer::sum); counts.merge("Other", 1, Integer::sum); counts.merge("Other", 1, Integer::sum); counts.merge("Other", 1, Integer::sum); System.out.println(counts.getOrDefault("Test", 0)); System.out.println(counts.getOrDefault("Other", 0)); System.out.println(counts.getOrDefault("Another", 0)); 

Output:

 2 3 0 

You can wrap this behavior in a class in a few lines of code:

 public class Counter<T> { final Map<T, Integer> counts = new HashMap<>(); public void add(T t) { counts.merge(t, 1, Integer::sum); } public int count(T t) { return counts.getOrDefault(t, 0); } } 

Use this:

 final Counter<String> counts = new Counter<>(); counts.add("Test"); counts.add("Test"); counts.add("Other"); counts.add("Other"); counts.add("Other"); System.out.println(counts.count("Test")); System.out.println(counts.count("Other")); System.out.println(counts.count("Another")); 

Output:

 2 3 0 
+11
source

I don’t know how much I know. But scala is very expressive, allowing you to cook something like this:

 def counts[T](s: Seq[T]) = s.groupBy(x => x).mapValues(_.length) 

Edit: Even more concise:

 def counts[T](s: Seq[T]) = s.groupBy(identity).mapValues(_.length) 
+7
source

Another version of scala, doing it in one go and avoiding .groupBy

 val l = List("a", "b", "b", "c", "b", "c", "b", "d") l.foldLeft(Map[String, Int]() withDefaultValue (0)) { (m, el) => m updated (el, m(el)+1)} //> res1: Map(a -> 1, b -> 4, c -> 2, d -> 1) 

or if you do not want a card with a default value of zero

 l.foldLeft(Map[String, Int]()) { (m, el) => m updated (el, m.getOrElse(el,0)+1)} 
+3
source

Basically, you should be good with the basic operations associated together. How:

 val s = Seq("apple", "oranges", "apple", "banana", "apple", "oranges", "oranges") s.groupBy(l => l).map(t => (t._1, t._2.length)) //1 s.count(_ == "apple") //2 

As a result:

 Map(banana -> 1, oranges -> 3, apple -> 3) //1 - result 3 //2 - result 
+2
source

Many years after I initially asked this question, I realized how trivial it was. My ultra-basic Scala solution:

 import scala.collection.mutable /** * Created by salim on 3/10/2017. */ case class Counter[T]() { lazy val state:mutable.Map[T,Int] = mutable.HashMap[T,Int]() def apply(i:T):Int = state.getOrElse(i,0) def count(i:T):Unit = { val newCount = 1 + this(i) state += (i -> newCount) } } 
0
source

Here is my recursive implementation of Scala using a modified map

 def counter[T](s: Seq[T]) = { import scala.collection.mutable.Map def counter_iter[T](s: Seq[T], m: Map[T, Int]): Map[T, Int]= { if (s.isEmpty) m else { m(s.head) += 1 counter_iter(s.tail, m) } } counter_iter(s, Map[T, Int]().withDefaultValue(0)) } 

for use:

 scala> counter(List(1,1,2,2,2,3,4)) res34: scala.collection.mutable.Map[Int,Int] = Map(2 -> 3, 4 -> 1, 1 -> 2, 3 -> 1) 
0
source

Source: https://habr.com/ru/post/981811/


All Articles