package blog import scala.annotation.tailrec import org.junit._ import Assert._ class SumByGroup { private val items = List(Stuff("A", 1), Stuff("A", 2), Stuff("B", 3), Stuff("B", 4)).sortBy {s => (s.label, s.number)} private val expectedResult = List(Stuff("A", 3), Stuff("B", 7)) @Test def classicSum = { var result: List[Stuff] = List() for (item <- items) { if (result.size > 0 && item.label == result.head.label) { result = Stuff(result.head.label, result.head.number + item.number) :: result.drop(1) } else { result = item :: result } } assertEquals(expectedResult, result.reverse) } @Test def recursiveSum = { @tailrec def sum(listOfPairs: List[Stuff], result: List[Stuff]): List[Stuff] = { listOfPairs match { case Nil => result case head :: tail => { val currentHead = if (result.size == 0) { Stuff(head.label, 0) } else { result.head } val newResult = if (currentHead.label == head.label) { Stuff(currentHead.label, currentHead.number + head.number) :: result.drop(1) } else { head :: result } sum(tail, newResult) } } } val result = sum(items, List()) assertEquals(expectedResult, result.reverse) } @Test def sumByGroupSolution1 = { val stuffsGroupedByLabel = items.groupBy(_.label) val result = stuffsGroupedByLabel map { t => Stuff(t._1, t._2 map { _.number } sum) } assertEquals(expectedResult, result) } @Test def sumByGroupSolution2 = { val stuffsGroupedByLabel = items.groupBy(_.label) def sumOfStuffsWithTheSameLabel(stuffs: List[Stuff]): Int = stuffs map { _.number } sum val result = stuffsGroupedByLabel map { t => Stuff(t._1, sumOfStuffsWithTheSameLabel(t._2)) } assertEquals(expectedResult, result) } @Test def sumByGroupSolution3 = { def sumStuffsWithTheSameLabel(stuffs: List[Stuff]): Int = stuffs map { _.number } sum def createStuffFromAListOfStuffs(keyAndListPair: Tuple2[String, List[Stuff]]): Stuff = Stuff(keyAndListPair._1, sumStuffsWithTheSameLabel(keyAndListPair._2)) val groupedByLabel = items.groupBy(_.label) val result = groupedByLabel map { createStuffFromAListOfStuffs(_) } assertEquals(expectedResult, result) } @Test def sumByGroupSolution4 = { val groupedByLabel = items.groupBy(_.label) val result = groupedByLabel map { case (label, stuffs) => Stuff(label, stuffs map { _.number } sum) } assertEquals(expectedResult, result) } @Test def sumByGroupSolution5 = { val calcSumOfStuff = (stuffs: Seq[Stuff]) => stuffs map { _.number } sum val groupedByLabel = items.groupBy { _.label } val resultGroupedByLabel = groupedByLabel mapValues { calcSumOfStuff } val result = resultGroupedByLabel map { t => Stuff(t._1, t._2) } assertEquals(expectedResult, result) } @Test def sumByGroupSolution6 = { val calcSumOfStuff = (stuffs: Seq[Stuff]) => stuffs map { _.number } sum val result = items.groupBy { _.label } mapValues { calcSumOfStuff } map { t => Stuff(t._1, t._2) } assertEquals(expectedResult, result) } } case class Stuff(val label: String, val number: Int)