gpt4 book ai didi

c# - 字典 到 DataTable

转载 作者:太空宇宙 更新时间:2023-11-03 10:57:31 25 4
gpt4 key购买 nike

我有一个非常奇怪的问题,不知道应该采取哪种方式来解决它。

我有一个 IEnumerable<Dictionary<string,object>>它可以包含一个或多个 IEnumerable<Dictionary<string,object>> .

现在,这个Dictionary需要导入到DataTable中,如果IEnumberable<Dictionary<string,object>>里面有 0 个 child ,那么 DataTable 应该只包含一行,列名作为字符串,RowData 作为对象(在本例中为字符串)。但是,如果有一个子项,则 DataTable 应包含与该子项相同的行数,以及来自父项的每行中的其他信息。

例如,父字典有这些值:

string, object---------------Name, MikeLastName, Tyson

IEnumerable Dictionary child has:

string, object----------------[0]ChildName, JohnChildAge, 10[1]ChildName, TonyChildAge, 12

Result should be:

Name    LastName     ChildName     ChildAge--------------------------------------------Mike    Tyson        John          10Mike    Tyson        Tony          12

Also, Parent IEnumerable can have many children IEnumerable, but they will all have the same size.

Does anyone have idea how to solve this?

static void Main(string[] args)
{
var child1 = new List<Dictionary<string, object>>();
var childOneDic = new Dictionary<string, object>
{
{ "ChildName", "John" },
{ "ChildAge", 10 }
};
child1.Add(childOneDic);

var child2 = new List<Dictionary<string, object>>();
var childTwoDic = new Dictionary<string, object>
{
{ "ChildName", "Tony" },
{ "ChildAge", 12 }
};
child2.Add(childTwoDic);

var parrent = new List<Dictionary<string, object>>();
var parrentDic = new Dictionary<string, object>
{
{ "Name", "Mike" },
{ "LastName", "Tyson" },
{ "child1", child1 },
{ "child2", child2 }
};
parrent.Add(parrentDic);

var table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("LastName");
table.Columns.Add("ChildName");
table.Columns.Add("ChildAge");
table = CreateTable(parrent, null, table);
}

static DataTable CreateTable(IEnumerable<Dictionary<string, object>> parrent,
DataRow row, DataTable table)
{
if (row == null)
{
row = table.NewRow();
}

foreach (var v in parrent)
{
foreach (var o in v)
{
if (o.Value.GetType().IsGenericType)
{
var dic = (IEnumerable<Dictionary<string, object>>) o.Value;
CreateTable(dic, row, table);
}
else
{
row[o.Key] = o.Value;
}
}
if (row.RowState == DataRowState.Added)
{
DataRow tempRow = table.NewRow();
tempRow.ItemArray = row.ItemArray;
table.Rows.Add(tempRow);
}
else
{
table.Rows.Add(row);
}
}

return table;
}

最佳答案

Linq 是这项工作的理想人选。我仍然认为你应该重新考虑设计,这是一件非常可怕的事情。应该这样做(并且没有任何硬编码):

var child1 = new List<IDictionary<string, object>>
{
new Dictionary<string, object> { { "ChildName", "John" }, { "ChildAge", 10 } }
};

var child2 = new List<IDictionary<string, object>>
{
new Dictionary<string, object> { { "ChildName", "Tony" }, { "ChildAge", 12 } }
};

var parent = new List<IDictionary<string, object>>
{
new Dictionary<string, object>
{
{ "Name", "Mike" },
{ "LastName", "Tyson" },
{ "child1", child1 },
{ "child2", child2 }
},
new Dictionary<string, object>
{
{ "Name", "Lykke" },
{ "LastName", "Li" },
{ "child1", child1 },
},
new Dictionary<string, object>
{
{ "Name", "Mike" },
{ "LastName", "Oldfield" }
}
};

CreateTable(parent);

static DataTable CreateTable(IEnumerable<IDictionary<string, object>> parents)
{
var table = new DataTable();

foreach (var parent in parents)
{
var children = parent.Values
.OfType<IEnumerable<IDictionary<string, object>>>()
.ToArray();

var length = children.Any() ? children.Length : 1;

var parentEntries = parent.Where(x => x.Value is string)
.Repeat(length)
.ToLookup(x => x.Key, x => x.Value);
var childEntries = children.SelectMany(x => x.First())
.ToLookup(x => x.Key, x => x.Value);

var allEntries = parentEntries.Concat(childEntries)
.ToDictionary(x => x.Key, x => x.ToArray());

var headers = allEntries.Select(x => x.Key)
.Except(table.Columns
.Cast<DataColumn>()
.Select(x => x.ColumnName))
.Select(x => new DataColumn(x))
.ToArray();
table.Columns.AddRange(headers);

var addedRows = new int[length];
for (int i = 0; i < length; i++)
addedRows[i] = table.Rows.IndexOf(table.Rows.Add());

foreach (DataColumn col in table.Columns)
{
object[] columnRows;
if (!allEntries.TryGetValue(col.ColumnName, out columnRows))
continue;

for (int i = 0; i < addedRows.Length; i++)
table.Rows[addedRows[i]][col] = columnRows[i];
}
}

return table;
}

这是我用过的一种扩展方法:

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
source = source.ToArray();
return Enumerable.Range(0, times).SelectMany(_ => source);
}

您可以以更惯用 的方式(我更喜欢)创建 addedRows 变量,但对于其他人来说,这可能不太可读。在一行中,像这样:

var addedRows = Enumerable.Range(0, length)
.Select(x => new
{
relativeIndex = x,
actualIndex = table.Rows.IndexOf(table.Rows.Add())
})
.ToArray();

这里棘手的部分是获得正确的旋转。在我们的案例中没什么大不了的,因为我们可以使用索引器。使用一组示例进行测试,如果有问题请告诉我..


另一种方法是预先计算标题(循环之前的数据表列),因为它无论如何都不会改变。但这也意味着额外一轮的枚举。至于哪个更有效,您将不得不对其进行测试。不过我发现第一个更优雅。

static DataTable CreateTable(IEnumerable<IDictionary<string, object>> parents)
{
var table = new DataTable();

//excuse the meaningless variable names

var c = parents.FirstOrDefault(x => x.Values
.OfType<IEnumerable<IDictionary<string, object>>>()
.Any());
var p = c ?? parents.FirstOrDefault();
if (p == null)
return table;

var headers = p.Where(x => x.Value is string)
.Select(x => x.Key)
.Concat(c == null ?
Enumerable.Empty<string>() :
c.Values
.OfType<IEnumerable<IDictionary<string, object>>>()
.First()
.SelectMany(x => x.Keys))
.Select(x => new DataColumn(x))
.ToArray();
table.Columns.AddRange(headers);

foreach (var parent in parents)
{
var children = parent.Values
.OfType<IEnumerable<IDictionary<string, object>>>()
.ToArray();

var length = children.Any() ? children.Length : 1;

var parentEntries = parent.Where(x => x.Value is string)
.Repeat(length)
.ToLookup(x => x.Key, x => x.Value);
var childEntries = children.SelectMany(x => x.First())
.ToLookup(x => x.Key, x => x.Value);

var allEntries = parentEntries.Concat(childEntries)
.ToDictionary(x => x.Key, x => x.ToArray());

var addedRows = Enumerable.Range(0, length)
.Select(x => new
{
relativeIndex = x,
actualIndex = table.Rows.IndexOf(table.Rows.Add())
})
.ToArray();

foreach (DataColumn col in table.Columns)
{
object[] columnRows;
if (!allEntries.TryGetValue(col.ColumnName, out columnRows))
continue;

foreach (var row in addedRows)
table.Rows[row.actualIndex][col] = columnRows[row.relativeIndex];
}
}

return table;
}

关于c# - 字典 <string, object> 到 DataTable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18923005/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com