Here is a sample using LINQ to process it. This uses the ever forgotten two parameter lambda version of Select
to get a position value for each type
. Since no column names were shown, I called the first column type
and the other
column stands for the rest of the data.
var db = new[] {
new { type = "test", other = 1 },
new { type = "test", other = 2 },
new { type = "test", other = 3 },
new { type = "test", other = 4 },
new { type = "test1", other = 5 },
new { type = "test1", other = 6 },
new { type = "test2", other = 7 },
new { type = "test2", other = 8 },
new { type = "test2", other = 9 },
new { type = "test2", other = 10 },
};
var ans = db.GroupBy(d => d.type)
.Select(dg => dg.Select((d, i) => new { d, i }))
.SelectMany(dig => dig)
.GroupBy(di => di.i)
.SelectMany(dig => dig.Select(di => di.d));
Basically this is an idiom (now I want a cool name like Schwartzian transform) for pivoting an IEnumerable<IEnumerable>>
which I then flatten.
I created an extension method to capture the pivot central idiom.
public static class IEnumerableIEnumerableExt {
// Pivot IEnumerable<IEnumerable<T>> by grouping matching positions of each sub-IEnumerable<T>
// src - source data
public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> src) =>
src.Select(sg => sg.Select((s, i) => new { s, i }))
.SelectMany(sg => sg)
.GroupBy(si => si.i)
.Select(sig => sig.Select(si => si.s));
public static DataTable ToDataTable(this IEnumerable<DataRow> src) {
var ans = src.First().Table.Clone();
foreach (var r in src)
ans.ImportRow(r);
return ans;
}
}
With this extension method, the answer becomes:
var ans2 = db.GroupBy(d => d.type)
.Pivot()
.SelectMany(dg => dg);
And if the source is a DataTable
, you can do this:
var ansdt = dt.AsEnumerable().GroupBy(r => r.Field<string>("type"))
.Pivot()
.SelectMany(rg => rg)
.ToDataTable();
Since there isn't really an easy way to order or sort a DataTable
, I added an extension method to convert the IEnumerable<DataRow>
to a new DataTable
.