我想根据他们的类型得到每种水果的数量。显然我需要以某种方式积累它们,但最好/最干净/等等是什么?
trait Fruit
case object Apple extends Fruit
case object Pear extends Fruit
case class Orange(variety: String) extends Fruit
val fruits = List(Pear, Apple, Pear, Pear, Apple, Orange("satsuma"), Orange("clementine"))
val numberOfOranges = ???
val numberOfApples = ???
val numberOfPears = ???
由于
答案 0 :(得分:4)
您可以将groupBy
与模式匹配结合使用:
val counts = fruits.groupBy{
case Apple => "apple"
case Pear => "pear"
case Orange(_) => "orange"
}.map{
case (key, values) => (key, values.size)
}
编辑如果您喜欢反射,而您的子类型没有类型参数,则可以使用fruits.groupBy(_.getClass)
(或getClass.getSimpleName
,如果您需要字符串)。
答案 1 :(得分:2)
您可以使用count
模式匹配来执行此操作:
val numberOfOranges = fruits.count { case Orange(_) => true
case _ => false }
以上将打印2.只需更改其他示例的模式匹配。
答案 2 :(得分:2)
这是一个使用反射的解决方案,尽管您需要使用模式匹配来使范围内的类型。您不能一般地迭代列表并获取每个元素的类型。
val orangeType = reflect.runtime.universe.typeOf[Orange]
val appleType = reflect.runtime.universe.typeOf[Apple.type]
val pearType = reflect.runtime.universe.typeOf[Pear.type]
def getType[T: reflect.runtime.universe.TypeTag](obj: T) =
reflect.runtime.universe.typeOf[T]
def typesOf[A](fs: List[A]): List[reflect.runtime.universe.Type] = {
fs.map {
// Use pattern match to reify type
case v @ Apple => getType(v)
case v @ Pear => getType(v)
case v @ Orange(_) => getType(v)
}
}
val fruitCount = typesOf(fruits).groupBy(identity).mapValues(_.size)
val numberOfOranges = fruitCount(orangeType)
val numberOfApples = fruitCount(appleType)
val numberOfPears = fruitCount(pearType)
老实说,这只是通过Scala反射类型进行分组,而不是像字符串(或其他一些原始类型)更明显的东西,并且很快变得过于复杂。最好的长期编码解决方案是提出自己的枚举并使用它,IMO。
答案 3 :(得分:1)
您可以在getClass
:
groupBy
fruits.groupBy(f => f.getClass.getSimpleName).mapValues(_.size)
// result: Map(Apple$ -> 2, Pear$ -> 3, Orange -> 2)