繁体   English   中英

是否有与Python 3的集合等效的scala / java。

[英]Is there a scala/java equivalent of Python 3's collections.Counter

我想要一个可以计算我拥有的对象数量的类-听起来比收集所有对象然后将它们分组更有效。

Python在collections.Counter中具有理想的结构,Java或Scala是否具有类似的类型?

从您链接的文档中:

Counter类类似于其他语言的包或多集。

Java没有Multiset类或类似类。 番石榴有一个MultiSet集合,可以完全满足您的需求。

在纯Java中,可以使用Map<T, Integer>和新的merge方法:

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));

输出:

2
3
0

您可以通过几行代码将这种行为包装在一个class中:

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);
    }
}

像这样使用:

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"));

输出:

2
3
0

据我所知。 但是scala具有很高的表现力,可以让您自己烹饪类似​​的东西:

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

编辑:更加简洁:

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

另一个scala版本, .groupBy一次操作即可避免使用.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)

或者如果您不想使用默认值为零的地图

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

通常,将基本操作链接在一起应该会很好。 喜欢:

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

结果:

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

在我最初问这个问题很多年后,我意识到它是多么微不足道。 我的超基本Scala解决方案是:

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)
  }
}

这是我的使用可变映射的尾递归Scala实现

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))
}

使用:

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM