减少对象列表的最快方法

时间:2016-04-18 10:28:34

标签: scala

我有一个清单:

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

对于上述问题,是否有更有效的解决方案?

2 个答案:

答案 0 :(得分:3)

除了Nyavro的建议,你可以(按照降低抽象级别的顺序,从而提高效率和降低可组合性):

  1. 使用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)
    
  2. 在这种情况下,您甚至可以一次完成所有事情:

    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)
        })
    }
    
  3. 将上述内容转换为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)
}
相关问题