[英]Normalize excel spreadsheet data (Columns to rows)
我正在尝试使用Microsoft Interop Excel对象规范化Excel电子表格中的数据。 基本上,我需要将列转换为从特定列偏移量开始的行。
Original Data:
ColumnA ColumnB ColumnC ColumnD ColumnE ColumnF
X Y 10 20 30 40
Normalized Data:
ColumnA ColumnB NewColumn Value
X Y ColumnC 10
X Y ColumnD 20
X Y ColumnE 30
X Y ColumnF 40
我的功能按预期工作。 但是,运行时间非常慢。 因此,我想知道是否使用其他框架(如OpenXML),效率会有所提高吗?
这是我使用Interop对象的代码:
public static void Normalize(string aFilePathName, string aSheetName, int aColOffSet, string aPivotColName, string aValueColName)
{
LOG.DebugFormat("Normaling data in file: {0}", aFilePathName);
LOG.DebugFormat("Sheet Name:{0} ColOffset:{1}", aSheetName, aColOffSet);
Excel.Application vExcel = new Excel.Application();
Excel.Workbook vWorkbook = null;
Excel.Worksheet vWsOriginal = null;
Excel.Worksheet vWsNormalized = null;
try
{
vExcel.Visible = false;
vWorkbook = vExcel.Workbooks.Open(aFilePathName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
vWsOriginal = vWorkbook.Worksheets[aSheetName];
string vNormalizedSheetName = string.Format("Normalized {0}", aSheetName);
bool vNormalizedSheetExists = (vWorkbook.Sheets.Cast<object>()
.Select(sheetValue => sheetValue as Excel.Worksheet))
.Any(wbSheet => wbSheet != null && wbSheet.Name == vNormalizedSheetName);
if (!vNormalizedSheetExists)
{
vWsNormalized = vWorkbook.Worksheets.Add(vWsOriginal, Type.Missing, Type.Missing, Type.Missing);
vWsNormalized.Name = vNormalizedSheetName;
}
else
{
vWsNormalized = vWorkbook.Worksheets[vNormalizedSheetName];
}
vWsNormalized.UsedRange.ClearContents();
long vTotalColumns = 1;
long vRowCounter = 1;
Excel.Range vWsRange = vWsOriginal.Cells[vRowCounter, vTotalColumns];
List<string> vHeaders = new List<string>();
while (vWsRange.Value2 != null)
{
vHeaders.Add(vWsRange.Value2.ToString());
vTotalColumns = vTotalColumns + 1;
vWsRange = vWsOriginal.Cells[vRowCounter, vTotalColumns];
}
// Insert the headers
for (int vHeaderCol = 1; vHeaderCol < aColOffSet; vHeaderCol++)
{
vWsNormalized.Cells[1, vHeaderCol].Value = vHeaders[vHeaderCol - 1];
}
vWsNormalized.Cells[1, aColOffSet].Value = aPivotColName;
vWsNormalized.Cells[1, aColOffSet + 1].Value = aValueColName;
long vNewRow = 2;
for (int vCol = aColOffSet; vCol < vTotalColumns; vCol++)
{
vRowCounter = 2;
while (((Excel.Range)vWsOriginal.Cells[vRowCounter, 1]).Value2 != null)
{
for (int j = 1; j < aColOffSet; j++)
{
vWsNormalized.Cells[vNewRow, j] = vWsOriginal.Cells[vRowCounter, j];
}
vWsNormalized.Cells[vNewRow, aColOffSet] = vWsOriginal.Cells[1, vCol];
vWsNormalized.Cells[vNewRow, aColOffSet + 1] = vWsOriginal.Cells[vRowCounter, vCol];
vRowCounter = vRowCounter + 1;
vNewRow = vNewRow + 1;
}
}
}
finally
{
vWorkbook.Close(Excel.XlSaveAction.xlSaveChanges, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(vWsNormalized);
Marshal.FinalReleaseComObject(vWsOriginal);
Marshal.FinalReleaseComObject(vWorkbook);
vExcel.Quit();
Marshal.FinalReleaseComObject(vExcel);
}
}
如果有可能提高性能,我愿意尝试任何其他开源框架。
谢谢
我能够提出一个更好的实施方案。 无需遍历每个单元格,而是利用Excel转置功能进行批量复制。
public static void Normalize2(string aFilePathName, string aSheetName, int aColOffSet, string aPivotColName, string aValueColName)
{
LOG.DebugFormat("Normaling data in file: {0}", aFilePathName);
LOG.DebugFormat("Sheet Name:{0} ColOffset:{1}", aSheetName, aColOffSet);
Excel.Application vExcel = new Excel.Application();
Excel.Workbook vWorkbook = null;
Excel.Worksheet vWsOriginal = null;
Excel.Worksheet vWsNormalized = null;
try
{
vExcel.Visible = false;
vWorkbook = vExcel.Workbooks.Open(aFilePathName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
vWsOriginal = vWorkbook.Worksheets[aSheetName];
//vWsOriginal.Name = string.Format("Original_{0}", aSheetName);
string vNormalizedSheetName = string.Format("Normalized {0}", aSheetName);
bool vNormalizedSheetExists = (vWorkbook.Sheets.Cast<object>()
.Select(sheetValue => sheetValue as Excel.Worksheet))
.Any(wbSheet => wbSheet != null && wbSheet.Name == vNormalizedSheetName);
if (!vNormalizedSheetExists)
{
vWsNormalized = vWorkbook.Worksheets.Add(vWsOriginal, Type.Missing, Type.Missing, Type.Missing);
vWsNormalized.Name = vNormalizedSheetName;
}
else
{
vWsNormalized = vWorkbook.Worksheets[vNormalizedSheetName];
}
vWsNormalized.UsedRange.ClearContents();
long vTotalColumns = 1;
long vRowCounter = 1;
Excel.Range vWsRange = vWsOriginal.Cells[vRowCounter, vTotalColumns];
List<string> vHeaders = new List<string>();
while (vWsRange.Value2 != null)
{
vHeaders.Add(vWsRange.Value2.ToString());
vTotalColumns = vTotalColumns + 1;
vWsRange = vWsOriginal.Cells[vRowCounter, vTotalColumns];
}
// Insert the headers
for (int vHeaderCol = 1; vHeaderCol < aColOffSet; vHeaderCol++)
{
vWsNormalized.Cells[1, vHeaderCol].Value = vHeaders[vHeaderCol - 1];
}
vWsNormalized.Cells[1, aColOffSet].Value = aPivotColName;
vWsNormalized.Cells[1, aColOffSet + 1].Value = aValueColName;
long vNewRow = 2;
long vValueColumns = vTotalColumns - aColOffSet;
vRowCounter = 2;
Excel.Range vHeaderData = vWsOriginal.Range[vWsOriginal.Cells[1, aColOffSet],
vWsOriginal.Cells[1, vTotalColumns - 1]];
string[] vPivotValueNames = new string[vTotalColumns - aColOffSet];
vHeaders.CopyTo(aColOffSet - 1, vPivotValueNames, 0, (int) (vTotalColumns - aColOffSet));
while (((Excel.Range)vWsOriginal.Cells[vNewRow, 1]).Value2 != null)
{
Excel.Range vStaticRowData = vWsOriginal.Range[vWsOriginal.Cells[vNewRow, 1],
vWsOriginal.Cells[vNewRow, aColOffSet - 1]];
Excel.Range vDynamicRowData = vWsOriginal.Range[vWsOriginal.Cells[vNewRow, aColOffSet],
vWsOriginal.Cells[vNewRow, vTotalColumns - 1]];
long vDestRowStart = vRowCounter;
long vDestRowEnd = (vRowCounter + vValueColumns) - 1;
Excel.Range vNormalizedStaticRowData = vWsNormalized.Range[vWsNormalized.Cells[vDestRowStart, 1],
vWsNormalized.Cells[vDestRowEnd, aColOffSet - 1]];
Excel.Range vNormalizedPivotValueRowData = vWsNormalized.Range[vWsNormalized.Cells[vDestRowStart, aColOffSet],
vWsNormalized.Cells[vDestRowEnd, aColOffSet]];
Excel.Range vNormalizedValueRowData = vWsNormalized.Range[vWsNormalized.Cells[vDestRowStart, aColOffSet + 1],
vWsNormalized.Cells[vDestRowEnd, aColOffSet + 1]];
vNormalizedStaticRowData.Value = vStaticRowData.Value;
vNormalizedPivotValueRowData.Value = vExcel.WorksheetFunction.Transpose(vHeaderData.Value);
vNormalizedValueRowData.Value = vExcel.WorksheetFunction.Transpose(vDynamicRowData.Value);
vNewRow = vNewRow + 1;
vRowCounter = vRowCounter + vValueColumns;
}
}
finally
{
vWorkbook.Close(Excel.XlSaveAction.xlSaveChanges, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(vWsNormalized);
Marshal.FinalReleaseComObject(vWsOriginal);
Marshal.FinalReleaseComObject(vWorkbook);
vExcel.Quit();
Marshal.FinalReleaseComObject(vExcel);
}
}
我最近不得不做类似的事情,并使用数据透视表向导找到了这个技巧: http : //www.launchexcel.com/pivot-table-flatten-crosstab/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.