Transform a collection

.net, c#, linq

Solution

Given these simplistic classes:

class C {
  public int A;
  public int B;
}
class R {
  public int A;
  public List<int> Bs = new List<int>();
}

You can do it like this:

var cs = new C[] {
  new C() { A = 1, B = 1 },
  new C() { A = 1, B = 2 },
  new C() { A = 2, B = 3 },
  new C() { A = 2, B = 4 },
  new C() { A = 1, B = 5 },
  new C() { A = 3, B = 6 }
};

var rs = cs.
  OrderBy(o => o.B).
  ThenBy(o => o.A).
  Aggregate(new List<R>(), (l, o) => {
    if (l.Count > 0 && l.Last().A == o.A) {
      l.Last().Bs.Add(o.B);
    }
    else {
      l.Add(new R { A = o.A, Bs = { o.B } });
    }
    return l;
  });

Note: In the above I assume that the Bs and then the As have to be sorted. If that's not the case, it's a simple matter of removing the sorting instructions:

var rs = cs.
  Aggregate(new List<R>(), (l, o) => {
    if (l.Count > 0 && l.Last().A == o.A) {
      l.Last().Bs.Add(o.B);
    }
    else {
      l.Add(new R { A = o.A, Bs = { o.B } });
    }
    return l;
  });

Problem

Have a collection of objects. Schematically: ``` [ { A = 1, B = 1 } { A = 1, B = 2 } { A = 2, B = 3 } { A = 2, B = 4 } { A = 1, B = 5 } { A = 3, B = 6 } ] ``` Need: ``` [ { A = 1, Bs = [ 1, 2 ] } { A = 2, Bs = [ 3, 4 ] } { A = 1, Bs = [ 5 ] } { A = 3, Bs = [ 6 ] } ] ``` Is it possible to LINQ such? Note: Ordering is important. So `Bs = [5]` can't be merged with `Bs = [1, 2]`

Original source