2016-04-18 16 views
3

Ich habe eine Liste zu reduzieren:schnellste Weg, um eine Liste von Objekten

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) 

Ich möchte reduzieren die oben aufgeführte Liste auf Namen und das Land basiert, so dass der Ausgang

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

Meine Lösung zu diesem ist:

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

Gibt es eine effizientere Lösung für das oben genannte Problem?

+1

Sie Personen ohne Doppelkarte (..) auf gruppierte Sammlung in einem Rutsch könnte erhalten – Nyavro

+0

Können Sie mir zeigen, wie? Danke – binshi

Antwort

3

Neben Nyavro Vorschlag, können Sie (in der Reihenfolge der abnehmenden Abstraktionsebene und damit sowohl die Effizienz erhöht und verringert composability):

  1. Zwischen Sammlungen Vermeiden Sie in persons.map(...).sum von persons.view.map(...).sum oder mehr direkt

    mit
    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. Für diesen Fall, dass Sie auch alles in einem einzigen Durchgang tun:

    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. Konvertieren Sie die oben genannten in eine while Schleife (wirklich nicht empfohlen, es sei denn, Sie brauchen wirklich die Leistung).

+0

Erste Option sieht gut aus IMO. –

3

Sie können einige Iterationen wie folgt speichern:

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