遍历数据表以从每一行获取两个特定值

时间:2020-08-28 05:12:30

标签: c# oracle datatable

我正在尝试遍历datatable并打印出

的值
  • 0,
  • 1和
  • 每行第4个单元格

感觉这应该可行,但是我可能以某种方式弄乱了循环。

 foreach (DataRow dr in dt.Rows)
 {
      for (int x = 0; x < dt.Rows.Count; x++)
      {
          Console.WriteLine(dt.Columns[0].ColumnName + " ");
          Console.WriteLine(dt.Rows[x].ItemArray[0].ToString() + " ");
          Console.WriteLine(dt.Columns[1].ColumnName + " ");
          Console.WriteLine(dt.Rows[x].ItemArray[1].ToString() + " ");
          Console.WriteLine(dt.Columns[4].ColumnName + " ");
          Console.WriteLine(dt.Rows[x].ItemArray[4].ToString() + " ");
       }
 }

上面的代码给我这个错误:

系统无法执行指定的程序。

3 个答案:

答案 0 :(得分:2)

删除其中一个循环:

                for (int x = 0; x < dt.Rows.Count; x++)
                {
                    Console.WriteLine(dt.Columns[0].ColumnName + " ");
                    Console.WriteLine(dt.Rows[x].ItemArray[0].ToString() + " ");
                    Console.WriteLine(dt.Columns[1].ColumnName + " ");
                    Console.WriteLine(dt.Rows[x].ItemArray[1].ToString() + " ");
                    Console.WriteLine(dt.Columns[4].ColumnName + " ");
                    Console.WriteLine(dt.Rows[x].ItemArray[4].ToString() + " ");
                }

                foreach (DataRow dr in dt.Rows){
                    Console.WriteLine($"{dr[0]} - {dr[1]} - {dr[4]}");
                }

答案 1 :(得分:1)

您无需在行上用for循环包围foreach循环。 (您根本没有使用dr

for (int idx = 0; idx < dt.Rows.Count; idx++)
{
    Console.WriteLine(dt.Columns[0].ColumnName + " ");
    Console.WriteLine(dt.Rows[idx].ItemArray[0] + " ");
    Console.WriteLine(dt.Columns[1].ColumnName + " ");
    Console.WriteLine(dt.Rows[idx].ItemArray[1] + " ");
    Console.WriteLine(dt.Columns[4].ColumnName + " ");
    Console.WriteLine(dt.Rows[idx].ItemArray[4] + " ");
}

更通用的版本:

int[] columnIndexes = new[] { 0, 1, 4 };
for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < columnIndexes.Length; columnIndex++)
    {
        Console.WriteLine(dt.Columns[columnIndex].ColumnName + " ");
        Console.WriteLine(dt.Rows[rowIndex].ItemArray[columnIndex] + " ");
    }
}

如果您要使用foreach遍历Rows集合,则可以这样做,但要复杂一些。

DataTable的Rows属性是DataRowCollection。它公开了GetEnumerator循环必不可少的foreach方法。

foreach (DataRow dr in dt.Rows)
{
    //dr does not provide you direct access to the ColumnName
}

您不能直接从DataRow访问ColumnName。所有需要做的就是为列名创建一个“查找表”,其中键是索引,值是列名。

int colIdx = 0;
var columnNames = dt.Columns
    .Cast<DataColumn>()
    .ToDictionary(_ => colIdx++, column => column.ColumnName);

之后,您的foreach循环将如下所示:

int[] columnIndexes = new[] {0, 1, 4};
foreach (DataRow row in dt.Rows)
{
    for (int columnIndex = 0; columnIndex < columnIndexes.Length; columnIndex++)
    {
        Console.WriteLine(columnNames[columnIndex] + " ");
        Console.WriteLine(row.ItemArray[columnIndex] + " ");
    }
}

答案 2 :(得分:0)

我只是想指出,您确实可以通过column name访问DataRow中的值。该功能在完整的.net框架和.net核心中都可用(因此,无论使用哪种版本,您都可以使用)。 当然这会对性能造成轻微影响,因为它似乎最终会进行Dictionary查找。

采用这种方法所获得的一个好处是,将来您对表结构的更改将不再那么依赖-这可能是一个值得考虑的折衷方案。

那么您的意图可以这样表达:

foreach (DataRow row in dt.Rows)
    Console.WriteLine($"{row["Col0"]} - {row["Col1"]} - {row["Col4"]}");

现在,假设您想放下foreach并前进LINQ

void Main()
{
    var dt = new DataTable();
    dt.Columns.Add("Col0", typeof(string));
    dt.Columns.Add("Col1", typeof(string));
    dt.Columns.Add("Col2", typeof(string));
    dt.Columns.Add("Col3", typeof(string));
    dt.Columns.Add("Col4", typeof(string));
    
    dt.Rows.Add("one","two","three","four","five");
    dt.Rows.Add("ten","eleven","twelve","thirteen","fourteen");

    var formattedItems = dt.Rows // declaring a lise you'd open yourself up to further processing the results rather than just pringint them
                            .Cast<DataRow>() // DataRow collection does implement IEnumerable through its base InternalDataCollectionBase class but we seem to need this cast in order to properly expose it
                            .Select(row => $"{row["Col0"]} - {row["Col1"]} - {row["Col4"]}") // and now we can unleash the LINQ
                            .ToList(); // depending on your further processing code you can either enumerate it now or have it sitting around until you actually need to loop through it
    
    Console.WriteLine(formattedItems.Aggregate(new StringBuilder(), (sb, s) => sb.AppendLine(s)).ToString()); // just slapping list items together in a string to print out for your convenience
}