here is my Problem:
I try to aggregate a List of Objects:
val list = List(Foo(1), Foo(2), Bar(2), Bar(3), Baz(5), Baz(3))
After the aggregation i want to have only one object for every aggregatable type in this list. In this Example Foo and Bar should be aggregatable where Baz isn’t, so the result should be:
List(Foo(3), Bar(5), Baz(5), Baz(3))
My Idea was to define a trait Aggregatable as follows:
trait Aggregatable[T] {
def aggregate(agg: T): T
}
case class Foo(val x: Int) extends Aggregatable[Foo] {
def aggregate(agg: Foo) = {
val x = (0 /: List(this, agg))((old, elem) => (old + elem.x))
new Foo(x)
}
}
case class Bar(val x: Int) extends Aggregatable[Bar] {
def aggregate(agg: Bar) = {
val x = (0 /: List(this, agg))((old, elem) => (old + elem.x))
new Bar(x)
}
}
case class Baz(val x: Int)
Well, I think this is the obvious part of the Problem…
In the next step I try to aggregate the list. First I group the list into lists of homogenious types:
val grouped = list.groupBy( _.getClass().toString() )
/* => grouped should be
* Map(
* class Foo ->
* List(Foo(1), Foo(2)),
* class Bar ->
* List(Bar(3), Bar(4)),
* class Baz ->
* List(Baz(5), Baz(3))
* )
*/
Now for the sake of simplicity lets now assume that we want to find out if the first two elements of the first list are aggregatable:
val firstList = grouped.toList.apply(0)._2 // List(Foo(1), Foo(2))
val a = firstList (0) // Foo(1)
val b = firstList (1) // Foo(2)
This is where my actual problem begins. To determine if a and b can be aggregated, there must be a way to ask if a and b inherit from the same type Aggregatable[T] for some fixed T.
My way to ask this was to define a type aggregatablePair:
type aggregatablePair = Pair[T, T] forSome { type T <: Aggregatable[T] }
Build a pair out of a and b:
val pair = (a, b)
and aggregate them if they are an aggregatablePair:
pair match {
case aggPair: aggregatablePair => aggPair._1.aggregate(aggPair._2)
case _ => println("pair is not aggregatable")
}
but this doesn’t work… the error is:
type mismatch;
found: aggPair._2.type (with underlying type T forSome { type T <: Aggregatable[T] })
required: T where type T <: Aggregatable[T]
In my opinion it sounds like the found type matches the required type… can anyone tell me why it dosn’t?
And what would be the right way to express what I want?
thank you for any help
I’ve found a quite “satisfying” solution to my problem. The general Idea is to add a method aggregateOrCons with result type List[Any] to the Aggregatable trait, which either aggregates two Objects if they are from the same type or returns a list containing the input arguments.
My input parameters are now being sorted instead of grouped by their class, because I only need to ensure that objects of the same type appear in a row.
In the next step I define a method to aggregate two objects of type Any. If both input arguments are of type Aggregatable, I apply the aggregatableOrCons method on them (which will result either the aggregation of the two arguments, if they are equal, or a list containing the arguments if they are not). If one of them is no Aggregatable a list containing the input arguments will be returned.
Now the only requirement left to be able to fold the list of sorted input artuments is a neutral element. It should aggregate with anything and should just return the input argument.
Now I can fold the sorted list