c# - 通过使用 DataTable 创建单独的组将数据清理到 DataTable 中
问题描述
第一栏 | 日期栏 | 数据列 | 组ID | 无效数据Fg 中文 | 2019 年 10 月 28 日 | 页眉 | 1 | 错误的 中文 | 2019 年 10 月 28 日 | 123-10-234-3333 | 1 | 错误的 中文 | 2019 年 10 月 28 日 | 页眉 | 2 | 错误的 中文 | 2019 年 10 月 28 日 | 133-11-334-4444 | 2 | 错误的 中文 | 2019 年 10 月 28 日 | 345-12-332-2233 | 2 | 错误的 中文 | 2019 年 10 月 28 日 | 页眉 | 3 | 错误的 中文 | 2019 年 10 月 28 日 | 123---2222 | 3 | 真的 中文 | 2019 年 10 月 28 日 | ---2334 | 3 | 真的
我有一个包含上述字段值的表。为了创建组,我使用了 foreach 并创建了两个单独的数据表
- 有效数据
- 无效数据。
我正在使用 C# 来编写代码:
List<DataRow> ValidData = below
第一栏 | 日期栏 | 数据列 中文 | 2019 年 10 月 28 日 | 标题 中文 | 2019 年 10 月 28 日 | 123-10-234-3333 中文 | 2019 年 10 月 28 日 | 标题 中文 | 2019 年 10 月 28 日 | 133-11-334-4444 中文 | 2019 年 10 月 28 日 | 345-12-332-2233
List<DataRow> InvalidData below
第一栏 | 日期栏 | 数据列 中文 | 2019 年 10 月 28 日 | 标题 中文 | 2019 年 10 月 28 日 | 123---2222 中文 | 2019 年 10 月 28 日 | ---2334
由于 Details3 缺少信息。详细信息是不完整的信息,并非完全为空。
由于我的数据没有 rowid,我添加了它们可能有助于分组。
以下是代码,请您查看并帮助更好地编写此代码。我无法 dataLines.Add(group.AsEnumerable().ToList()); 错误:谢谢。
DataTable dt = new DataTable();
var dtable = dt.AsEnumerable().GroupBy(r => r.Field<string>("GroupId"));
foreach (var group in dtable)
{
var InvalidData = group.Where(r => r.Field<string>("InvalidDataFg") == "True").FirstOrDefault();
if (InvalidData != null)
invalidDataLines.Add(group.AsEnumerable().ToList());
else
dataLines.Add(group.AsEnumerable().ToList());
}
解决方案
我无法 dataLines.Add(group.AsEnumerable().ToList());
您的问题的直接答案是:
List<DataRow> datalines = ...
dataLines.AddRange(group);
您要求查看代码。如果您打算在更大的项目中使用此代码更长的时间,那么我看到了几个问题。
你应该致力于你的关注点分离:你的类就像意大利面条一样交织在一起。这使得在没有其他类的情况下很难使用它们,因此很难在类似情况下重用它们。很难测试它们,因此很难更改它们,因为您无法测试更改的效果。
将您的问题分解为更小的问题:分离关注点:
- 看起来你有三个序列:原始数据、有效数据和无效数据
- 显然你想把这些排序到数据表中,也许你想从数据表中提取它们
- 您想从原始数据中提取所有有效数据,您想从原始数据中提取无效数据。
因此,好的设计是将 DataTable 部分与序列中数据的提取分开。
class OriginalData // TODO: invent a proper name
{
public string FirstColumn {get; set;} // TODO: invent a proper name, it is not a column!
public DateTime Date {get; set;}
public string Data {get; set;}
public int GroupId {get; set;}
public bool IsValid {get; set;}
}
class ValidData // TODO: invent a proper name
{
public string FirstColumn {get; set;}
public DateTime Date {get; set;}
public string Data {get; set;}
}
class InvalidData {...}
您需要表格来存储数据:
class OriginalDataTable : DataTable
{
// Define the columns
private DataColumn columnDate = new DataColumn(...);
private DataColumn columnIsValid = new DataColumn(...);
...
public OriginalDataTable() : base()
{
base.Columns.Add(columnDate);
base.Columns.add(columnIsValid);
...
}
public OriginalDataTable(IEnumerable<OriginalData> initialData) : this()
{
this.AddRange(initialData);
}
public void Add(OriginalData data)
{
DataRow row = this.CreateFilledRow(data);
base.Rows.Add(row);
}
public void AddRange(IEnumerable<OriginalData> data)
{
foreach (OriginalData item in data)
this.Add(item);
}
private DataRow CreateFilledRow(OriginalData data)
{
DataRow row = base.NewRow();
row[columnDate] = data.Date;
row[columnIsValid] = data.IsValid;
...
return row;
}
... // Other methods
}
访问数据有两种方式:你认为这个DataTable代表一个OriginalData序列,还是给你一个OriginalData序列?换句话说:它实现IEnumerable<OriginalData>
了,还是有方法IEnumerable<OriginalData> GetData()
?无论您使用哪种都是口味问题:
IEnumerable<OriginalData> initialData = ...
OriginalDataTable table = new OriginalDataTable(initialData);
IEnumerable<OriginalData> dataToAdd = ...
table.AddRange(dataToAdd);
// If you implement IEnumreable<OriginalData> you can do:
foreach (OriginalData data in table) {...}
// othwerwise you do:
foreach (OriginalData data in table.GetData()) {...}
代码类似:
public IEnumerable<OriginalData> GetOriginalData()
{
foreach (DataRow row in base.Rows)
{
OriginalData data = CreateFromDataRow(row);
yield return data;
}
}
public IEnumerator<OriginalData> GetEnumerator()
{
return this.GetOriginalData.GetEnumerator();
}
public OriginalData CreateFromDataRow(row)
{
return new OriginalData
{
IsValid = (bool)row[this.columnIsValid];
...
}
}
您还需要将 OriginalData 转换为 ValidData 或 InvalidData 的过程:
public static ValidData ToValidData(this OriginalData data)
{
return new ValidData()
{
...
}
}
当然还有一种从原始数据中提取 ValidData 的方法:
public static IEnumerable<ValidData> ToValidData(this IEnumerable<OriginalData> originalData)
{
return originaldata.GroupBy(originaItem => originalItem.GroupId)
.Select(... => ToValidData(...));
}
对你的其他类和表做类似的事情。这看起来工作量很大,但你可以在 30 分钟内完成。
现在从有效和无效数据中提取很容易。将结果放在另一个表中也很容易。
IEnumerable<OriginalData> initialData = ...
// Put it in a table and add some data. Two statements only!
OriginalDataTable originalTable = new OriginalDataTable(initialData);
IEnumerable<OriginalData> dataToAdd = ...
originalTable.AddRange(dataToAdd);
// Easy to extract the data, and to convert into ValidData: One statement!
IEnumerable<ValidData> validData = originalTable.GetData().ToValidData();
// easy to put the result in a table
DataTable validDataTable = new ValidDataTable(validData);
// and easy to get the valid data items back:
foreach (ValidData validItem in ValidDataTable.GetData())
{
ProcessValidData(validItem);
}
结论
如果您将长期使用这些表,如果您期望更改,如果您需要测试代码,最好将表与数据分开,并将数据与处理分开。
- 小程序更容易理解
- 这些程序更容易单独测试
- 在其他情况下更容易重用它们。您在创建 ToInvalidData 方法时已经看到了这一点:可以重用从原始表中提取数据的代码
- 更改数据更容易:例如,如果您想将 Boolean IsValid 的显示从 0/1 更改为测试 True/False 或 TRUE/FALSE,您所要做的就是更改表类。所有其他类和转换方法不必更改。
所有这一切都在大约 30 分钟内完成!
推荐阅读
- google-sheets - 除了引用的单元格通过 not(isblank) 为空白之外,Arrayformula 正在整个列上扩展
- c# - Devexpress 报告:表重复 C#
- python - xlearn 预测错误给出的 mse 与函数的输出不同
- c - %s 正在跳过整个打印行 - 没有用户输入
- anaconda - 无法将 Seaborn 正确导入我的 IBM Watson-Studio
- java - 通过反向代理的 Java Paho MQTT 客户端连接
- c# - 在 Visual Studio 2015 中调试 nunit 测试时出错
- amazon-web-services - 用于查询另一个区域中存在的 DynamoDB 的 lambda 函数?
- sql-server - 防止 MS SQL Studio 系统连接到多个数据库
- javascript - HTML5 表单验证初始“工具提示”消息