【发布时间】:2014-07-21 13:59:30
【问题描述】:
我有以下课程
public class DaysCoverReport
{
public string SupplierCode { get; set; }
public string CustomerCode { get; set; }
public DateTime StartDate { get; set; }
public int Dur { get; set;}
}
我通过解析 .csv 文件创建了一个列表:
IEnumerable<DaysCoverReport> daysCoverList =
DaysCoverReport.ParseDaysCoverReport(file).ToList();
我想通过StartDate 和Dur 为每个日期旋转列表,并通过 EPPlus 库将以下内容输出到 Excel 工作簿:
Start Date
Customer Code Item Desc. 7/16/2014 7/17/2014 7/18/2014
1234-6789 Test Item A 10 2 3
45-9003 Test Item B 5 1 8
我认为最好的方法是使用 LINQ 旋转数据并通过以下方式将旋转后的数据传递给 EPPlus:
worksheet.Cells["A1"].LoadFromCollection(pivotedDataList, true)
这是我目前所拥有的:
var query = (from d in daysCoverList
group d by new {d.ItemDescription, d.CustomerCode, d.StartDate}
into grp
select new
{
grp.Key.CustomerCode,
grp.Key.ItemDescription,
grp.Key.StartDate,
Dur = grp.Sum(d => d.Dur)
}).ToList();
但这并不是我想要的,因为该列表包含 2600 行,而如果我在 Excel 中执行此操作,它会合并到大约 10 行。我想我可能需要对 query 对象再执行一项操作。
编辑:使用下面@a-h 的答案,下面是完整的解决方案。请注意,此解决方案包括总计行和列,并且可能没有优化,因为我对 LINQ 还很陌生。
IEnumerable<DaysCoverReport> daysCoverList = DaysCoverReport.ParseDaysCoverReport(file).ToList();
//Group by Customer Code and Item Description
var grouped = daysCoverList.GroupBy(d => new
{
d.CustomerCode,
d.ItemDescription
})
.Select(grp => new
{
grp.Key.CustomerCode,
grp.Key.ItemDescription,
GroupedByDate = grp.ToLookup(g => g.StartDate.Date, g => g.Dur),
DurSum = grp.Sum(g => g.Dur)
})
.OrderBy(grp => grp.CustomerCode)
.ToList();
var totalsByDate = daysCoverList.GroupBy(d => new
{
d.StartDate.Date,
})
.Select(d => new
{
d.Key.Date,
GroupedByDate = d.ToLookup(g => g.StartDate.Date, g => g.Dur),
})
.ToList();
//Get distinct list of dates for pivot columns
var columns = grouped
.SelectMany(grp => grp.GroupedByDate.Select(g => g.Key))
.Distinct()
.OrderBy(d => d).ToList();
using (ExcelPackage package = new ExcelPackage(new FileInfo(saveFileName)))
{
ExcelWorksheet pivot = package.Workbook.Worksheets.Add("Traffic Light Report");
pivot.Cells["A1"].Value = "Sum of Dur";
pivot.Cells["A1"].Style.Font.Bold = true;
pivot.Cells["C1"].Value = "Start Date";
pivot.Cells["C1"].Style.Font.Bold = true;
for(int i = 1; i <= columns.Count + 3; i++)
{
var headerCell = pivot.Cells[2, i];
if (i == 1)
headerCell.Value = "Customer Code";
else if (i == 2)
headerCell.Value = "Item Description";
else if (i == columns.Count + 3)
headerCell.Value = "Grand Total";
else
headerCell.Value = columns[i - 3].ToString("MM/dd/yyyy");
headerCell.Style.Font.Bold = true;
}
int j = 3;
foreach (var line in grouped)
{
for (int i = 1; i <= columns.Count + 3; i++)
{
var cell = pivot.Cells[j, i];
if (i == 1)
cell.Value = line.CustomerCode;
else if (i == 2)
cell.Value = line.ItemDescription;
else if (i == columns.Count + 3)
cell.Value = line.DurSum;
else
cell.Value = line.GroupedByDate.Contains(columns[i - 3]) ? line.GroupedByDate[columns[i - 3]].Sum() : 0;
}
j++;
}
//Write total row
var totalRowCell = pivot.Cells[j, 1];
totalRowCell.Value = "Grand Total";
totalRowCell.Style.Font.Bold = true;
int k = 3;
foreach (var date in totalsByDate)
{
totalRowCell = pivot.Cells[j, k];
totalRowCell.Value = date.GroupedByDate.Contains(columns[k - 3]) ? date.GroupedByDate[columns[k - 3]].Sum() : 0;
k++;
}
pivot.Cells[j, k].Value = daysCoverList.Sum(d => d.Dur);
//Apply conditional formatting for Traffic Light
ExcelAddress formatRangeAddress = new ExcelAddress(3, 3, grouped.Count + 2, columns.Count + 2);
var red = pivot.ConditionalFormatting.AddLessThanOrEqual(formatRangeAddress);
red.Style.Fill.BackgroundColor.Color = System.Drawing.Color.Red;
red.Formula = "0";
var amber = pivot.ConditionalFormatting.AddBetween(formatRangeAddress);
amber.Style.Fill.BackgroundColor.Color = System.Drawing.Color.Orange;
amber.Formula = "0";
amber.Formula2 = "15";
var green = pivot.ConditionalFormatting.AddBetween(formatRangeAddress);
green.Style.Fill.BackgroundColor.Color = System.Drawing.Color.Green;
green.Formula = "15";
green.Formula2 = "45";
var blue = pivot.ConditionalFormatting.AddGreaterThan(formatRangeAddress);
blue.Style.Fill.BackgroundColor.Color = System.Drawing.Color.Blue;
blue.Formula = "45";
pivot.Cells[pivot.Dimension.Address].AutoFitColumns();
package.Save();
}
【问题讨论】:
-
当您按日期(例如 StartDate)分组时,您可能需要丢弃小时、分钟、秒等。最简单的方法是使用 StartDate.Date。我没有看到你的数据,但这可能解释了你的代码和 Excel 之间的差异。
-
好点。我肯定会忽略这一点,但是日期列包含以下格式的日期
d/mm/yyyy,所以它工作正常。真的,我现在只需要执行实际的支点,但我不知道该怎么做。 -
你可以试试 ToString() 方法的日期时间:msdn.microsoft.com/en-us/library/8kb3ddd4.aspx