使用LINQ旋转数据

26 c# linq pivot-table

我试图看看我是否可以使用LINQ来解决我遇到的问题.我有一个包含Enum(TypeCode)和User对象的项目集合,我需要将其展平以显示在网格中.这很难解释,所以让我举一个简单的例子.

集合有这样的项目:

TypeCode | User 
---------------
1        | Don Smith  
1        | Mike Jones  
1        | James Ray  
2        | Tom Rizzo  
2        | Alex Homes  
3        | Andy Bates  
Run Code Online (Sandbox Code Playgroud)

我需要输出为:

1          | 2          | 3  
Don Smith  | Tom Rizzo  | Andy Bates  
Mike Jones | Alex Homes |  
James Ray  |            |  
Run Code Online (Sandbox Code Playgroud)

感谢任何可以帮助我的人!我尝试使用foreach这样做,但是我不能这样做,因为我要在foreach中将新项目插入到集合中,从而导致错误.

Mar*_*ell 22

我并不是说这是一个很好的方式 - 但它是一个支点......

    // sample data
    var data = new[] {
        new { Foo = 1, Bar = "Don Smith"},
        new { Foo = 1, Bar = "Mike Jones"},
        new { Foo = 1, Bar = "James Ray"},
        new { Foo = 2, Bar = "Tom Rizzo"},
        new { Foo = 2, Bar = "Alex Homes"},
        new { Foo = 3, Bar = "Andy Bates"},
    };
    // group into columns, and select the rows per column
    var grps = from d in data
              group d by d.Foo
              into grp
              select new {
                  Foo = grp.Key,
                  Bars = grp.Select(d2 => d2.Bar).ToArray()
              };

    // find the total number of (data) rows
    int rows = grps.Max(grp => grp.Bars.Length);

    // output columns
    foreach (var grp in grps) {
        Console.Write(grp.Foo + "\t");
    }
    Console.WriteLine();
    // output data
    for (int i = 0; i < rows; i++) {
        foreach (var grp in grps) {
            Console.Write((i < grp.Bars.Length ? grp.Bars[i] : null) + "\t");
        }
        Console.WriteLine();
    }
Run Code Online (Sandbox Code Playgroud)


小智 11

Marc的答案给出了稀疏矩阵,它不能直接泵入Grid.
我试图从Vasu提供链接扩展代码,如下所示:

public static Dictionary<TKey1, Dictionary<TKey2, TValue>> Pivot3<TSource, TKey1, TKey2, TValue>(
    this IEnumerable<TSource> source
    , Func<TSource, TKey1> key1Selector
    , Func<TSource, TKey2> key2Selector
    , Func<IEnumerable<TSource>, TValue> aggregate)
{
    return source.GroupBy(key1Selector).Select(
        x => new
        {
            X = x.Key,
            Y = source.GroupBy(key2Selector).Select(
                z => new
                {
                    Z = z.Key,
                    V = aggregate(from item in source
                                  where key1Selector(item).Equals(x.Key)
                                  && key2Selector(item).Equals(z.Key)
                                  select item
                    )

                }
            ).ToDictionary(e => e.Z, o => o.V)
        }
    ).ToDictionary(e => e.X, o => o.Y);
} 
internal class Employee
{
    public string Name { get; set; }
    public string Department { get; set; }
    public string Function { get; set; }
    public decimal Salary { get; set; }
}
public void TestLinqExtenions()
{
    var l = new List<Employee>() {
    new Employee() { Name = "Fons", Department = "R&D", Function = "Trainer", Salary = 2000 },
    new Employee() { Name = "Jim", Department = "R&D", Function = "Trainer", Salary = 3000 },
    new Employee() { Name = "Ellen", Department = "Dev", Function = "Developer", Salary = 4000 },
    new Employee() { Name = "Mike", Department = "Dev", Function = "Consultant", Salary = 5000 },
    new Employee() { Name = "Jack", Department = "R&D", Function = "Developer", Salary = 6000 },
    new Employee() { Name = "Demy", Department = "Dev", Function = "Consultant", Salary = 2000 }};

    var result5 = l.Pivot3(emp => emp.Department, emp2 => emp2.Function, lst => lst.Sum(emp => emp.Salary));
    var result6 = l.Pivot3(emp => emp.Function, emp2 => emp2.Department, lst => lst.Count());
}
Run Code Online (Sandbox Code Playgroud)

*虽然不能说出表现.


Tal*_*joe 5

您可以使用Linq的.ToLookup以您要查找的方式进行分组.

var lookup = data.ToLookup(d => d.TypeCode, d => d.User);
Run Code Online (Sandbox Code Playgroud)

然后将它放入消费者可以理解的形式中.例如:

//Warning: untested code
var enumerators = lookup.Select(g => g.GetEnumerator()).ToList();
int columns = enumerators.Count;
while(columns > 0)
{
  for(int i = 0; i < enumerators.Count; ++i)
  {
    var enumerator = enumerators[i];
    if(enumator == null) continue;
    if(!enumerator.MoveNext())
    { 
      --columns;
      enumerators[i] = null;
    }
  }
  yield return enumerators.Select(e => (e != null) ? e.Current : null);
}
Run Code Online (Sandbox Code Playgroud)

将它放在IEnumerable <>方法中,它(可能)将返回User的集合(列)的集合(行),其中null放在没有数据的列中.