我有一个如下所示的数据表
Dosage Drug Patient
-----------------------------------
25 Indocin David
50 Enebrel,Crozine Sam
10 Hydralazine Christoff
21 Combivent Janet
100 Dilantin Melanie
应根据逗号分割转换为如下所示的
Dosage Drug Patient
------------------------------
25 Indocin David
50 Enebrel Sam
50 Crozine Sam
10 Hydralazine Christoff
21 Combivent Janet
100 Dilantin Melanie
我做了以下代码,没有得到预期的结果。有人可以提出答案吗?
private static void ProcessDatatable(DataTable dt)
{
DataTable dtnew = new DataTable();
IEnumerable<string[]> allRowValues = dt.AsEnumerable()
.Select(r => r.Field<string>(1).Split(','));
dtnew = allRowValues.ToDataTable();
}
扩展方法:
public static DataTable ToDataTable<T>(this IEnumerable<T> collection, string tableName)
{
DataTable tbl = ToDataTable(collection);
tbl.TableName = tableName;
return tbl;
}
public static DataTable ToDataTable<T>(this IEnumerable<T> collection)
{
DataTable dt = new DataTable();
Type t = typeof(T);
PropertyInfo[] pia = t.GetProperties();
// Create the columns in the DataTable
foreach (PropertyInfo pi in pia)
{
dt.Columns.Add(pi.Name, pi.PropertyType);
}
// Populate the table
foreach (T item in collection)
{
DataRow dr = dt.NewRow();
dr.BeginEdit();
foreach (PropertyInfo pi in pia)
{
dr[pi.Name] = pi.GetValue(item, null);
}
dr.EndEdit();
dt.Rows.Add(dr);
}
return dt;
}
答案 0 :(得分:2)
您认为您想要的是这个
IEnumerable<object[]> allRowValues = dataTable.AsEnumerable()
.SelectMany(dataRow =>
dataRow.Field<string>(1).Split(',').Select(drug => new[] { dataRow[0], drug, dataRow[2] }));
但是您真正想要的是:
IEnumerable<Record> allRowValues = dataTable.AsEnumerable()
.Select(dataRow => new Record(dataRow))
.SelectMany(record => record.SplitDrugs());
// ...
public class Record
{
public int Dosage { get; }
public string Drug { get; }
public string Patient { get; }
public Record(int dosage, string drug, string patient)
{
Dosage = dosage;
Drug = drug;
Patient = patient;
}
public Record(DataRow dataRow)
: this((int)dataRow["Dosage"], (string)dataRow["Drug"], (string)dataRow["Patient"])
{
}
public IEnumerable<Record> SplitDrugs()
{
return Drug.Split(',').Select(drug => new Record(Dosage, drug, Patient));
}
}
简短的说明:您想用花哨的LINQ来解决太多的问题,比如从数据表中提取信息,逐行处理行,应用业务逻辑并将结果合并到新的数据表中。这是编写容易出错,无法读取,无法测试,不稳定和无法维护的代码的好方法。
最终将感谢您选择第二个选项的人员的不完整列表:
在此期间,我将为您节省一些时间来调试将allRowValues
(在您的情况下为IEnumerable<string[]>
类型)转换回DataTable
的过程。如果您认为它将包含3列,那么您错了。相反,它将包含诸如Length
,LongLength
,Rank
等列。...查看properties Array class以找出原因。
OP在另一个答案下的注释中完善了原始意图。
...,但是我只是发布了数据表的原型,实际上实际上有180列。我需要在逗号分隔的值分开的情况下在newRow.ItemArray中手动添加所有180列吗?更简单的方法?
是的,有一种更简单的方法。涉及泛型,您可以将使用范围扩展到此有限的用例之外:
// extension method
public static DataTable ExpandColumn<T>(this DataTable dataTable, string columnName,
Func<T, IEnumerable<T>> expandField)
{
var clonedDataTable = dataTable.Clone();
var columnIndex = dataTable.Columns.IndexOf(columnName);
var column = dataTable.Columns[columnIndex];
foreach (var dataRow in dataTable.AsEnumerable())
{
var valueToExpand = dataRow.Field<T>(column);
var expandedValues = expandField(valueToExpand);
var originalValues = dataRow.ItemArray;
foreach (var value in expandedValues)
{
originalValues[columnIndex] = value;
clonedDataTable.Rows.Add(originalValues);
}
}
return clonedDataTable;
}
// usage
var dataTableNew = dataTable.ExpandColumn<string>("Drug", drug => drug.Split(','));
上述扩展方法通过复制原始行来克隆DataTable
实例,并通过为每个值应用expandField
函数来扩展指定列中的值。
我仍然希望您从编辑中得到的教训中吸取教训,并对设计进行三思。
答案 1 :(得分:1)
我对C#几乎不满意,因此我不得不以老式的方式进行操作,但它确实有效。
public partial class Form1 : Form
{
private DataTable dt;
private DataTable dtExpanded;
public Form1()
{
InitializeComponent();
LoadTable();
LoadExpandedTable();
}
//Dosage Drug Patient
private void LoadTable()
{
dt = new DataTable();
using (SqlConnection cn = new SqlConnection("Your connection string"))
{
using (SqlCommand cmd = new SqlCommand("Select * From DrugDoses", cn))
{
cn.Open();
dt.Load(cmd.ExecuteReader());
}
}
dataGridView1.DataSource = dt;
}
private void LoadExpandedTable()
{
dtExpanded = new DataTable();
dtExpanded.Columns.Add("Dose");
dtExpanded.Columns.Add("Drug");
dtExpanded.Columns.Add("Patient");
foreach (DataRow r in dt.Rows)
{
string s = (string)r["Drug"];
if(s.Contains(","))
{
string[] splitName = s.Split(',');
foreach (string drug in splitName)
{
DataRow newRow = dtExpanded.NewRow();
newRow.ItemArray = new Object[] { r["Dosage"], drug , r["Patient"]};
dtExpanded.Rows.Add(newRow);
}
}
else
{
dtExpanded.Rows.Add(r.ItemArray);
}
}
dataGridView2.DataSource = dtExpanded;
}
}