【问题标题】:LINQ Transform/PivotLINQ 转换/透视
【发布时间】:2018-11-26 14:02:55
【问题描述】:

我正在从事一个项目,我正在使用实体框架将信息保存在简单的 POCO 类中,对其进行操作,然后输出到 OpenXML 报告。

我有以下示例类:

public class ClassA
{
   property string SectionName {get;set;}
   property string Status {get;set;}
   property int SingleValue {get;set;}
   property int CoupleValue {get;set;}
   property int FamilyValue {get;set;}
}

这可以填充例如:

SectionName = 'Category 1'
Status = 'Opening'
SingleValue = 0
CoupleValue = 0
FamilyValue = 0

SectionName = 'Category 1'
Status = 'Current'
SingleValue = 1
CoupleValue = 1
FamilyValue = 1

SectionName = 'Category 1'
Status = 'Closing'
SingleValue = 2
CoupleValue = 2
FamilyValue = 2

SectionName = 'Category 2'
Status = 'Opening'
SingleValue = 0
CoupleValue = 0
FamilyValue = 0

SectionName = 'Category 2'
Status = 'Current'
SingleValue = 1
CoupleValue = 1
FamilyValue = 1

SectionName = 'Category 2'
Status = 'Closing'
SingleValue = 2
CoupleValue = 2
FamilyValue = 2

在我的代码中,我有一个 ICollection:

ICollection<ClassA> Classes;

有没有办法使用 LINQ 将此集合转换/转置为准备输出:

SectionName | ValueLabel | OpeningValue | CurrentValue | ClosingValue
Category 1  | Single     | 0            | 1            | 2
Category 1  | Couple     | 0            | 1            | 2
Category 1  | Family     | 0            | 1            | 2
Category 2  | Single     | 0            | 1            | 2
Category 2  | Couple     | 0            | 1            | 2
Category 2  | Family     | 0            | 1            | 2

【问题讨论】:

    标签: entity-framework linq poco


    【解决方案1】:

    你可以想出这样的东西:

    var l = new List<Test>
    {
        new Test { SectionName = "Cat 1", Status = "Opening", SingleValue = 0, CoupleValue = 0, FamilyValue = 0 },
        new Test { SectionName = "Cat 1", Status = "Current", SingleValue = 1, CoupleValue = 1, FamilyValue = 1 },
        new Test { SectionName = "Cat 1", Status = "Closing", SingleValue = 2, CoupleValue = 2, FamilyValue = 2 },
        new Test { SectionName = "Cat 2", Status = "Opening", SingleValue = 0, CoupleValue = 0, FamilyValue = 0 },
        new Test { SectionName = "Cat 2", Status = "Current", SingleValue = 1, CoupleValue = 1, FamilyValue = 1 },
        new Test { SectionName = "Cat 2", Status = "Closing", SingleValue = 2, CoupleValue = 2, FamilyValue = 2 },
    };
    
    const string strValue = "Value";
    var cats = l.Select(x => x.SectionName).Distinct().ToArray();
    var catNo = cats.Length;
    var valProps = new Test().GetType().GetProperties().Where(p => p.Name.EndsWith(strValue)).ToArray();
    var vals = valProps.Select(p => p.Name.Split(strValue).First()).ToArray();
    var valsNo = vals.Length;
    var elNo = catNo * valsNo;
    var dictOpClCu = l.GroupBy(t => t.Status).ToDictionary(g => g.Key, g => g
        .SelectMany(t => valProps.Select(p => (int) p.GetValue(t, null))).ToArray());
    
    var l2 = new List<Test2>();
    var currCat = -1;
    var currVal = -1;
    for (var i = 0; i < elNo; i++)
    {
        l2.Add(new Test2
        {
            Section = cats[i % (elNo / catNo) != 0 ? currCat : ++currCat],
            ValueLabel = vals[++currVal % valsNo],
            OpeningValue = dictOpClCu["Opening"][i],
            ClosingValue = dictOpClCu["Closing"][i],
            CurrentValue = dictOpClCu["Current"][i]
        });
    }
    

    测试类:

    public class Test
    {
        public string SectionName { get; set; }
        public string Status { get; set; }
        public int SingleValue { get; set; }
        public int CoupleValue { get; set; }
        public int FamilyValue { get; set; }
    }
    
    public class Test2
    {
        public string Section { get; set; }
        public string ValueLabel { get; set; }
        public int OpeningValue { get; set; }
        public int CurrentValue { get; set; }
        public int ClosingValue { get; set; }
    
        public override string ToString() => $"{Section} | {ValueLabel} | {OpeningValue} | {CurrentValue} | {ClosingValue}";
    }
    

    【讨论】:

      【解决方案2】:

      您可以通过在SectionName 上进行分组并将这些组转换为Status 上的字典来使用 LINQ:

      var ans = Classes.GroupBy(c => c.SectionName)
                       .Select(cg => new { Key = cg.Key, Values = cg.ToDictionary(c => c.Status) })
                       .SelectMany(cg => new[] {
                          new Output { SectionName = cg.Key, ValueLabel = "Single", OpeningValue = cg.Values["Opening"].SingleValue, CurrentValue = cg.Values["Closing"].SingleValue, ClosingValue = cg.Values["Current"].SingleValue },
                          new Output { SectionName = cg.Key, ValueLabel = "Couple", OpeningValue = cg.Values["Opening"].CoupleValue, CurrentValue = cg.Values["Closing"].CoupleValue, ClosingValue = cg.Values["Current"].CoupleValue },
                          new Output { SectionName = cg.Key, ValueLabel = "Family", OpeningValue = cg.Values["Opening"].FamilyValue, CurrentValue = cg.Values["Closing"].FamilyValue, ClosingValue = cg.Values["Current"].FamilyValue }
                       }).ToList();
      

      【讨论】:

        猜你喜欢
        • 2016-01-22
        • 2016-11-21
        • 1970-01-01
        • 1970-01-01
        • 2019-12-17
        • 2011-08-09
        • 1970-01-01
        • 2015-04-25
        • 2013-07-05
        相关资源
        最近更新 更多