Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Pivot IEnumerable<T>

Tags:

c#

.net

I needed to "pivot" or "rotate" a collection of objects. The example will clear up what I needed to do:

var people = new List<Person>(new[] {
                new Person{ Name="Ronnie",Age=25, HairColor="Brown",EyeColor="Blue"},
                new Person{ Name="Tina",Age=25, HairColor="Brown",EyeColor="Green"},
                new Person{ Name="Lukus",Age=4, HairColor="Blonde",EyeColor="Blue"}    
            });

DataTable rotatedData = people.Pivot("Name", "Property");                

/* Results In:
* ___________________________________________
* Property  |  Ronnie  |   Tina    |   Lukus
* ___________________________________________
* Age       |  25      |   25      |   4
* HairColor |  Brown   |   Brown   |   Blonde
* EyeColor  |  Blue    |   Green   |   Blue
* ____________________________________________
*/

Here is the code that I wrote accomplish this:

/// <summary>Converts an IEnumerable into a pivoted DataTable object.</summary>
/// <param name="collection">The IEnumerable object to pivot and convert.</param>
/// <param name="headingMember">The name of a public field or property member of type T to be used as column name's in the pivoted DataTable object.</param>
/// <param name="membersHeading">The name of the column that lists the public fields and properties of type T.</param>        
static DataTable Pivot<T>(this IEnumerable<T> collection, string headingMember, string membersHeading)
{
    // get object information
    var type = typeof(T);
    var members = new List<MemberInfo>();
    members.AddRange(type.GetProperties(BindingFlags.Public | BindingFlags.Instance));
    members.AddRange(type.GetFields(BindingFlags.Public | BindingFlags.Instance));

    // create dataTable and establish schema
    var dt = new DataTable();
    dt.Columns.Add(membersHeading);
    foreach (var item in collection)
    {
        var member = members.Single(x => x.Name == headingMember);
        if (member is FieldInfo)                        
        {
            FieldInfo fieldInfo = (FieldInfo)member;
            dt.Columns.Add(fieldInfo.GetValue(item).ToString(), fieldInfo.FieldType);
        }

        if (member is PropertyInfo)
        {
            PropertyInfo propInfo = (PropertyInfo)member;
            dt.Columns.Add(propInfo.GetValue(item, null).ToString(), propInfo.PropertyType);
        }
    }

    // add rows to table
    foreach (MemberInfo member in members.Where(x => x.Name != headingMember))
    {
        var row = dt.NewRow();
        row[0] = member.Name;
        int i = 1;

        foreach (var item in collection)
        {
            if (member is FieldInfo)
                row[i++] = ((FieldInfo)member).GetValue(item);

            if (member is PropertyInfo)
                row[i++] = ((PropertyInfo)member).GetValue(item, null);
        }

        dt.Rows.Add(row);
    }

    return dt;
}

Is there What would be a better way to do this?

like image 588
Ronnie Overby Avatar asked Nov 18 '09 15:11

Ronnie Overby


1 Answers

You could Pivot an IEnumerable simply by using Group on the name. Assuming the name is distinct. Once you've pivoted the data, you can Convert IEnumerable to DataTable.

like image 194
Yuriy Faktorovich Avatar answered Oct 13 '22 00:10

Yuriy Faktorovich