将 C# 列表列表导出到 Excel

发布于 2024-07-26 04:10:25 字数 1499 浏览 7 评论 0 原文

使用 C#,是否有直接方法将列表列表(即 List>)导出到 Excel 2003?

我正在解析大型文本文件并导出到 Excel。 一次写入一个单元格会产生太多的开销。 我选择使用 List 这样我就不必担心指定行数或列数。

目前,我等到文件末尾,然后将 List> 的内容放入二维数组中。 然后可以将该数组设置为 Excel.Range 对象的值。 它有效,但似乎我应该能够获取我的列表列表,而不必担心行数或列数,并将其从 A1 转储到工作表中的任何位置。

下面是我想要替换或改进的代码片段:

object oOpt = System.Reflection.Missing.Value; //for optional arguments
Excel.Application oXL = new Excel.Application();
Excel.Workbooks oWBs = oXL.Workbooks;
Excel._Workbook oWB = oWBs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel._Worksheet oSheet = (Excel._Worksheet)oWB.ActiveSheet;

int numberOfRows = outputRows.Count;
int numberOfColumns = int.MinValue;

//outputRows is a List<List<object>>
foreach (List<object> outputColumns in outputRows)
{
        if (numberOfColumns < outputColumns.Count)
        { numberOfColumns = outputColumns.Count; }
}

Excel.Range oRng = oSheet.get_Range("A1", oSheet.Cells[numberOfRows,numberOfColumns]);

object[,] outputArray = new object[numberOfRows,numberOfColumns];

for (int row = 0; row < numberOfRows; row++)
{
        for (int col = 0; col < outputRows[row].Count; col++)
        {
                outputArray[row, col] = outputRows[row][col];
        }
}

oRng.set_Value(oOpt, outputArray);

oXL.Visible = true;
oXL.UserControl = true;

这可行,但我宁愿直接在 Excel 中使用列表,而不是仅仅为了 Excel 而进行创建数组的中间步骤。 有任何想法吗?

Using C#, is there a direct way to export a List of Lists (i.e., List<List<T>>) to Excel 2003?

I am parsing out large text files and exporting to Excel. Writing one cell at a time creates way too much overhead. I chose to use List<T> so that I would not have to worry about specifying the number of rows or columns.

Currently, I wait until end of file, then put the contents of my List<List<object>> into a 2-dimensional array. Then the array can be set as the value of an Excel.Range object. It works, but it seems like I should be able to take my List of Lists, without worrying about the number of rows or columns, and just dump it into a worksheet from A1 to wherever.

Here's a snippet of the code I'd like to replace or improve on:

object oOpt = System.Reflection.Missing.Value; //for optional arguments
Excel.Application oXL = new Excel.Application();
Excel.Workbooks oWBs = oXL.Workbooks;
Excel._Workbook oWB = oWBs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel._Worksheet oSheet = (Excel._Worksheet)oWB.ActiveSheet;

int numberOfRows = outputRows.Count;
int numberOfColumns = int.MinValue;

//outputRows is a List<List<object>>
foreach (List<object> outputColumns in outputRows)
{
        if (numberOfColumns < outputColumns.Count)
        { numberOfColumns = outputColumns.Count; }
}

Excel.Range oRng = oSheet.get_Range("A1", oSheet.Cells[numberOfRows,numberOfColumns]);

object[,] outputArray = new object[numberOfRows,numberOfColumns];

for (int row = 0; row < numberOfRows; row++)
{
        for (int col = 0; col < outputRows[row].Count; col++)
        {
                outputArray[row, col] = outputRows[row][col];
        }
}

oRng.set_Value(oOpt, outputArray);

oXL.Visible = true;
oXL.UserControl = true;

This works, but I'd rather use the List directly to Excel than having the intermediary step of creating an array just for the sake of Excel. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

掩饰不了的爱 2024-08-02 04:10:25

从战略上讲,你做得正确。 正如 Joe 所说,通过一次性传递整个值数组来执行单元格值分配比逐个循环单元格要快得多。

Excel 基于 COM,因此通过 .NET 互操作与 Excel 进行操作。 不幸的是,互操作不了解泛型,因此您不能将 List 传递给它。 或类似的。 二维数组确实是唯一的出路。

也就是说,有几种方法可以清理代码,使其更易于管理。 以下是一些想法:

(1) 如果您使用 .NET 3.0,则可以使用 LINQ 将代码从: 缩短

int numberOfColumns = int.MinValue;

foreach (List<object> outputColumns in outputRows)
{
        if (numberOfColumns < outputColumns.Count)
        { numberOfColumns = outputColumns.Count; }
}

为单行:

int numberOfColumns = outputRows.Max(list => list.Count);

(2) 不要使用 _Worksheet_Workbook 接口。 请改用 WorksheetWorkbook。 请参阅此处的讨论:Excel 互操作:_Worksheet 或 Worksheet?

(3) 考虑使用 Range.Resize 方法,该方法在 C# 中为 Range.get_Resize。 不过,这是一个难以抉择的问题——我实际上喜欢你设置范围大小的方式。 但我认为您可能想了解这一点。 例如,此处的行:

Excel.Range oRng = oSheet.get_Range("A1", oSheet.Cells[numberOfRows,numberOfColumns]);

可以更改为:

Excel.Range oRng = 
    oSheet.get_Range("A1", Type.Missing)
        .get_Resize(numberOfRows, numberOfColumns);

(4) 您不必将 Application.UserControl 设置为 true。 让 Excel 对用户可见就足够了。 UserControl 属性没有按照您想象的那样执行。 (请参阅此处的帮助文件)如果您想控制是否无论用户是否可以控制 Excel,您都应该使用工作表保护,或者如果您想锁定用户,您可以设置 Application.Interactive = false。 (这不是一个好主意。)但如果您希望允许用户使用 Excel,那么只需使其可见就足够了。

总的来说,考虑到这些,我认为您的代码可能看起来像这样:

object oOpt = System.Reflection.Missing.Value; //for optional arguments
Excel.Application oXL = new Excel.Application();
Excel.Workbooks oWBs = oXL.Workbooks;
Excel.Workbook oWB = oWBs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel.Worksheet oSheet = (Excel.Worksheet)oWB.ActiveSheet;

//outputRows is a List<List<object>>
int numberOfRows = outputRows.Count;
int numberOfColumns = outputRows.Max(list => list.Count);

Excel.Range oRng = 
    oSheet.get_Range("A1", oOpt)
        .get_Resize(numberOfRows, numberOfColumns);

object[,] outputArray = new object[numberOfRows, numberOfColumns];

for (int row = 0; row < numberOfRows; row++)
{
    for (int col = 0; col < outputRows[row].Count; col++)
    {
        outputArray[row, col] = outputRows[row][col];
    }
}

oRng.set_Value(oOpt, outputArray);

oXL.Visible = true;

希望这有帮助......

迈克

Strategically, you are doing it correctly. As Joe says, it is massively faster to execute cell value assignments by passing an entire array of values in one shot rather than by looping through the cells one by one.

Excel is COM based and so operates with Excel via the .NET interop. The interop is ignorant of generics, unfortunately, so you cannot pass it a List<T> or the like. A two dimensional array really is the only way to go.

That said, there are a few ways to clean up your code to make it a bit more manageable. Here are some thoughts:

(1) If you are using .NET 3.0, you can use LINQ to shorten your code from:

int numberOfColumns = int.MinValue;

foreach (List<object> outputColumns in outputRows)
{
        if (numberOfColumns < outputColumns.Count)
        { numberOfColumns = outputColumns.Count; }
}

to a single line:

int numberOfColumns = outputRows.Max(list => list.Count);

(2) Don't use the _Worksheet or _Workbook interfaces. Make use of Worksheet or Workbook instead. See here for a discussion: Excel interop: _Worksheet or Worksheet?.

(3) Consider making use of the Range.Resize method, which comes through as Range.get_Resize in C#. This is a toss-up though -- I actually like the way you are setting your range size. But it's something that I thought that you might want to know about. For example, your line here:

Excel.Range oRng = oSheet.get_Range("A1", oSheet.Cells[numberOfRows,numberOfColumns]);

Could be changed to:

Excel.Range oRng = 
    oSheet.get_Range("A1", Type.Missing)
        .get_Resize(numberOfRows, numberOfColumns);

(4) You do not have to set the Application.UserControl to true. Making Excel visible to the user is enough. The UserControl property is not doing what you think it does. (See the help files here) If you want to control whether the user can control Excel or not, you should utilze Worksheet protection, or you could set Application.Interactive = false if you want to lock out your users. (Rarely a good idea.) But if you want to allow the user to use Excel, then simply making it visible is enough.

Overall, with these in mind, I think that your code could look something like this:

object oOpt = System.Reflection.Missing.Value; //for optional arguments
Excel.Application oXL = new Excel.Application();
Excel.Workbooks oWBs = oXL.Workbooks;
Excel.Workbook oWB = oWBs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel.Worksheet oSheet = (Excel.Worksheet)oWB.ActiveSheet;

//outputRows is a List<List<object>>
int numberOfRows = outputRows.Count;
int numberOfColumns = outputRows.Max(list => list.Count);

Excel.Range oRng = 
    oSheet.get_Range("A1", oOpt)
        .get_Resize(numberOfRows, numberOfColumns);

object[,] outputArray = new object[numberOfRows, numberOfColumns];

for (int row = 0; row < numberOfRows; row++)
{
    for (int col = 0; col < outputRows[row].Count; col++)
    {
        outputArray[row, col] = outputRows[row][col];
    }
}

oRng.set_Value(oOpt, outputArray);

oXL.Visible = true;

Hope this helps...

Mike

两仪 2024-08-02 04:10:25

将二维数组传递到 Excel 比一次更新一个单元格要快得多。

使用列表列表中的值创建一个二维对象数组,将 Excel 范围重新调整为数组的维度,然后调用 range.set_Value,传递二维数组。

It's much faster to pass a two-dimensional array to Excel than to update cells one at a time.

Create a 2-dimensional array of objects with values from your list of lists, redimension the Excel range to the dimensions of your array, and then call range.set_Value, passing your two-dimensional array.

暗藏城府 2024-08-02 04:10:25
List<"classname"> getreport = cs.getcompletionreport();

var getreported = getreport .Select(c => new { demographic = c.rName);

希望这有帮助

,其中 cs.getcompletionreport() 是参考类文件是应用程序的业务层

List<"classname"> getreport = cs.getcompletionreport();

var getreported = getreport .Select(c => new { demographic = c.rName);

hopes this helps

where cs.getcompletionreport() is reference class file is Business Layer for App

随波逐流 2024-08-02 04:10:25

对于未来的搜索者:确实,如果您想将列表复制到 Excel,则必须粘贴 object[,] (二维)。 万一有人有一维列表,您可以仅运行一个第二维为 1 的 for 循环

List<DateTime> listDate; //I'm filling it with data from datagridview
...
object[,] outDate = new object[listDate.Count, 1];
for(int row = 0; row < listDate.Count; row++)
{
    outDate[row, 0] = listDate[row];
}

For future searchers: It is true that if you want to copy list to excel you have to paste object[,] (2 dimensional). Just in case someone has one dimensional list you can run just one for loop with second dimesion 1:

List<DateTime> listDate; //I'm filling it with data from datagridview
...
object[,] outDate = new object[listDate.Count, 1];
for(int row = 0; row < listDate.Count; row++)
{
    outDate[row, 0] = listDate[row];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文