我有一个清单:
case class Person(name:String, salary:Int, cars:Int, country:String)
val a = Person("gin", 100, 2, "Ind")
val b = Person("gin", 200, 1, "Ind")
val c = Person("gin", 50, 1, "US")
val d = Person("bin", 10, 0, "US")
val e = Person("bin", 20, 2, "UK")
val f = Person("bin", 30, 5, "Ind")
val list = List(a, b, c, d, e, f)
我想根据名称和国家/地区缩小上面的列表,以便输出
Person("gin", 300, 3, "Ind")
Person("gin", 50, 1, "US")
Person("bin", 10, 0, "US")
Person("bin", 20, 2, "UK")
Person("bin", 30, 5, "Ind")
我的解决方案是:
listBuffer.groupBy(p => p.name -> p.country).map {
case (key, persons) => key -> (persons.map(_.salary).sum, persons.map(_.cars).sum)
}.map {
case ((name, coutry), (ss, cs)) => Person(name, ss, cs, coutry)
}
对于上述问题,是否有更有效的解决方案?
答案 0 :(得分:3)
除了Nyavro的建议,你可以(按照降低抽象级别的顺序,从而提高效率和降低可组合性):
使用persons.map(...).sum
或更直接
persons.view.map(...).sum
中使用中间集合
def sumBy[A, B](xs: Seq[A])(f: A => B)(implicit n: Numeric[B]) =
xs.foldLeft(n.zero) { (a, b) => n.plus(a, f(b)) }
sumBy(persons)(_.salary)
在这种情况下,您甚至可以一次完成所有事情:
listBuffer.foldLeft(Map.empty[(String, String), Person]) {
(map, p) =>
val key = (p.name, p.country)
map.updated(key, (map.get(key) match {
case None => p
case Some(oldP) =>
Person(p.name, p.salary + oldP.salary, p.cars + oldP.cars, p.country)
})
}
将上述内容转换为while
循环(除非您确实需要性能,否则不建议使用)。
答案 1 :(得分:3)
您可以保存一些迭代:
list
.groupBy(person => person.name->person.country)
// Collect Persons in one go:
.map {
case ((name,cuntry), persons) =>
// Collect total salary and cars in one go:
val (ts, tc) = persons.foldLeft ((0,0)) {
case ((salary,cars), item) => (salary+item.salary,cars+item.cars)
}
Person(name, ts, tc, cuntry)
}