我有一个项目,允许用户通过左边连接到DataTable
(通过帮助方法转换为List<T>
)将列添加到DataTable
。目前,我已经实现了这项工作:
public static DataTable ListToDataTable<T>(this IList<T> data)
{
DataTable dt = new DataTable();
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
dt.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T t in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(t);
}
dt.Rows.Add(values);
}
return dt;
}
//for purposes of this demo, the first column in leftTable is always the
//column that's joined on
public static DataTable JoinWithList<T>(this DataTable leftTable, IList<T> data,string propertyToAdd)
{
var rightTable = new DataTable();
rightTable = data.ListToDataTable();
var joiningColumn = leftTable.Columns[0].ColumnName;
var columnIndex = 0;
//find the index of type T whose property is the same as leftTable's
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
if (prop.Name ==joiningColumn)
{
columnIndex = i;
}
}
var results = (from u in leftTable.AsEnumerable()
join s in rightTable.AsEnumerable()
on u[0] equals s[columnIndex] into ps
from p in ps.DefaultIfEmpty()
select new
{
MembershipId = u[0],
UserName = u[1],
//some sort of function to iterate over and add columns here
Salary = p == null ? 0.01 : p[propertyToAdd] = p[propertyToAdd]
}).ToList().ListToDataTable();
return results;
}
我希望能够传入一个List<string>
作为最后一个参数,并且select new
块内部有一个可变数量的列,这些列被添加到新的匿名类型中。
答案 0 :(得分:1)
从功能上思考。 尝试隔离基本案例并提供可以直接翻译成您选择的函数语言的递归定义。
让我们看看{ML} F#中join
的定义是什么:
_ join [] = []
[] join _ = []
H::T join L =
append
(L |> choose (match H) |> map (e -> (H, e)))
(T join L)
您需要正确构建match
函数,比较正确的列,以及传递给map
的函数来构建新行(在我的示例中只是一个元组)。
在C#中(不太优雅,效率低但希望在填写Match
和Create
后完成),通用版本可能如下所示:
public bool Match<A, B>(A a, B b)
{
// Match code
return true;
}
public C Create<A, B, C>(A a, B b)
{
// Create new record
return default(C);
}
public IList<C> Join<A, B, C>(IList<A> a, IList<B> b)
{
if(!a.Any() || !b.Any()) return new List<C>();
var aHead = a[0];
var bMatches = b.Where(bEl => Match(aHead, bEl));
var newCs = bMatches.Select(bEl => Create<A, B, C>(aHead, bEl)).ToList();
newCs.AddRange(Join<A, B, C>(a.Skip(1).ToList(), b)); // Recursive call
return newCs;
}