【问题标题】:C# Split DataTable by specific DataRow indexesC# 按特定的 DataRow 索引拆分 DataTable
【发布时间】:2018-09-19 13:12:02
【问题描述】:

我试图在stackoverflow上找到任何解决方案,但没有找到。

我有一个 DataTable,从 excel 表中获得。这是一个不清楚的表,它包含许多子表(以标题开头)和它们上面的其他必要信息(可能包含空行)。例如:

Line1 : Other data...
[empty line]
Line2: Other data...
[empty line]
...................   
ColA   |   ColB   |   Type   |
------------------------------
AAA    |   BBB    |   IN     |
AAA    |   BBB    |   OUT    |
AAA    |   BBB    |   IN     |

Line1 : Other data...
[empty line]
Line2: Other data...
[empty line]
...................    
ColA   |   ColB   |   Type   |
------------------------------
AAA    |   BBB    |   IN     |
AAA    |   BBB    |   OUT    |
AAA    |   BBB    |   OUT    |

我想将数据表拆分为多个数据表,这些数据表以许多必要信息行开头,然后是表本身,并以空行结尾。结果,我必须得到 DataTable[] 数据类型。

我试图获取数据表部分最后一行的索引(如果 DataRow 包含“in”或“out”并且下一个索引包含空行),但我不知道是否是一个好的代码和进一步拆分数据表的好解决方案:

var indexes = dataTable.AsEnumerable()
    .Where(x => x.ItemArray.All(rowCell => rowCell.ToString() == string.Empty))
    .Where(
       x => dataTable.Rows[dataTable.Rows.IndexOf(x) - 1].ItemArray.Any(
             item => Regex.Match(
                   item.ToString(),
                   "^in|out$",
                   RegexOptions.IgnoreCase).Success))
    .Select(x => dataTable.Rows.IndexOf(x)).ToArray();

我有两个 Where linq 条件来检查是否存在包含“in”或“out”的话。

如何按这些索引拆分 DataTable?为此,我想找到一个类似的 Linq Expression。结果,我必须得到以下表格:

表 #1

Line1 : Other data...
[empty line]
Line2: Other data...
[empty line]
...................   
ColA   |   ColB   |   Type   |
------------------------------
AAA    |   BBB    |   IN     |
AAA    |   BBB    |   OUT    |
AAA    |   BBB    |   IN     |

表 #2

Line1 : Other data...
[empty line]
Line2: Other data...
[empty line]
...................    
ColA   |   ColB   |   Type   |
------------------------------
AAA    |   BBB    |   IN     |
AAA    |   BBB    |   OUT    |
AAA    |   BBB    |   OUT    |

我知道如何进一步处理这些数据,但我不知道如何拆分数据表。

【问题讨论】:

  • 如果只是 IN || OUT,我建议使用 String.Equals() 而不是 Regex。
  • @MwBakker String.Equals() 性能更好?
  • 需要更少的系统资源,所以是的
  • 感谢您的建议。

标签: c# linq


【解决方案1】:
var selectedIndexes = from row in dataTable.AsEnumerable()
                          where (row.Text.Equals("IN") || row.Text.Equals("OUT"))
                                 && dataTable.Rows[dataTable.Rows.IndexOf(row) - 1]
                          select dataTable.Rows.IndexOf(row);

可能会成功,尽管这是未经测试的代码。

编辑:

由于您更新后的问题告诉我您正在处理 csv 文件,因此我强烈建议您使用 CSVHelper Nuget。

文档可以在这里找到:

https://joshclose.github.io/CsvHelper/

【讨论】:

  • 我想将带有这些索引的 DataTable 拆分为包含多个 DataTable 对象的数组。已经为获取这些索引实现了 linq 表达式。
  • 对不起,那我不确定你的意思。也许其他人得到了实现。
  • 例如,indexes = new [] {243}。第一个 DataTable 从 0 到 243 行索引开始,最后一个 DataTable - 从 244 开始到结束。我想我应该使用 SkipTake 但我不知道该怎么做。
  • 顺便说一句,我仍然建议在处理大量记录时使用上述语法来节省一些性能。
  • 如果我做对了,你想要所有的行,除了那些“多行”或不包含值的行?
【解决方案2】:

最后,我找到了解决方案。我受到以下问题答案的启发:Split datatable into multiple fixed sized tables

根据MwBakker用户的建议,我对索引识别码做了一点改动。

var indexes = dataTable.AsEnumerable()
      .Where(x => x.ItemArray.All(rowCell => rowCell.ToString() == string.Empty))
      .Where(
         x => dataTable.Rows[dataTable.Rows.IndexOf(x) - 1].ItemArray.Any(
           item => string.Equals(item.ToString(), "In")
                   || string.Equals(item.ToString(), "Out")))
      .Select(x => dataTable.Rows.IndexOf(x)).ToArray();

我创建了按索引拆分数据表行的扩展方法:

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> enumerable, int[] indexes)
    {
        // Sort array.
        indexes = indexes.OrderBy(x => x).ToArray();
        var itemsReturned = 0;
        var list = enumerable.ToList();
        var count = list.Count;
        short i = 0;

        while (itemsReturned < count)
        {
            int currentChunkSize = i < indexes.Length
                                       ? Math.Min(indexes[i] - itemsReturned, count - itemsReturned)
                                       : count - itemsReturned;
            yield return list.GetRange(itemsReturned, currentChunkSize);
            itemsReturned += currentChunkSize;
            i++;
        }
    }

接下来,我做了一个foreach循环:

var dataTables = dataTable.AsEnumerable().Split(indexes)
    .Select(rows => rows.CopyToDataTable());    

foreach (var table in dataTables)
{
    // ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-14
    • 2017-01-30
    • 1970-01-01
    • 2020-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多