我正在尝试以下方法:给定动态对象列表,使用提供的列列表执行GROUP BY。这是我到目前为止所做的:
using Newtonsoft.Json;
private static void Main(string[] args)
{
dynamic[] data = {
new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1"},
new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1", G = "G1"},
new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", H = "H1", I = "I1"}
};
var newList = data.GroupBy(row => new { row.A, row.B, row.C, row.D, row.E })
.Select(
y =>
new
{
A = y.Key.A, B = y.Key.B, C = y.Key.C, D = y.Key.D, E = y.Key.E,
Children = y.ToList()
});
var str = JsonConvert.SerializeObject(newList);
Console.Read();
}
这符合我的需要。但是,我想删除一些显示为Children
字段一部分的其他列。这是我现在为str
获得的输出:
[
{
"A":"A1",
"B":"B1",
"C":"C1",
"D":"D1",
"E":"E1",
"Children":[
{
"A":"A1",
"B":"B1",
"C":"C1",
"D":"D1",
"E":"E1",
"F":"F1"
},
{
"A":"A1",
"B":"B1",
"C":"C1",
"D":"D1",
"E":"E1",
"F":"F1",
"G":"G1"
},
{
"A":"A1",
"B":"B1",
"C":"C1",
"D":"D1",
"E":"E1",
"H":"H1",
"I":"I1"
}
]
}
]
我理想的是以下内容:
[
{
"A":"A1",
"B":"B1",
"C":"C1",
"D":"D1",
"E":"E1",
"Children":[
{
"E":"E1",
"F":"F1"
},
{
"F":"F1",
"G":"G1"
},
{
"H":"H1",
"I":"I1"
}
]
}
]
有关如何实现这一目标的任何建议?我所知道的是,对象中可能存在一定数量的字段(例如,A,B,C,D,E),但是无法控制其他字段(例如,F,G,H等)< / p>
答案 0 :(得分:1)
您可以使用ExpandoObject
类仅存储每个项目唯一的属性和反射来选择这些唯一属性。
这就是为什么我设法在LinqPad中划伤:
dynamic[] data =
{
new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1" },
new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1", G = "G1" },
new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", H = "H1", I = "I1" }
};
var keyProperties = new[] { "A", "B", "C", "D", "E" };
var newList = data.GroupBy(row => new { row.A, row.B, row.C, row.D, row.E }).Select(
y => new
{
A = y.Key.A,
B = y.Key.B,
C = y.Key.C,
D = y.Key.D,
E = y.Key.E,
Children = y.Select(
item =>
{
IEnumerable<dynamic> itemProps = item.GetType().GetProperties();
List<dynamic> properties =
itemProps.Where(p => !Enumerable.Contains(keyProperties, p.Name)).ToList();
var result = new ExpandoObject();
foreach (var property in properties)
{
var value = property.GetValue(item, null);
if (value != null)
{
((IDictionary<string, object>)result).Add(property.Name, value);
}
}
return result;
}).ToList()
});
var str = JsonConvert.SerializeObject(newList);
结果是:
[
{
"A": "A1",
"B": "B1",
"C": "C1",
"D": "D1",
"E": "E1",
"Children": [
{
"F": "F1"
},
{
"F": "F1",
"G": "G1"
},
{
"H": "H1",
"I": "I1"
}
]
}
]
修改强>
要合并子级别的元素,您需要稍微更改投影。
首先,Select
变为SelectMany
以返回KeyValuePair<string, object>
的集合,随后将按名称分组并连接成数组:
Children = y.SelectMany(item =>
{
IEnumerable<dynamic> itemProps = item.GetType().GetProperties();
List<dynamic> properties = itemProps.Where(p => !Enumerable.Contains(keyProperties,p.Name)).ToList();
var result = new ExpandoObject();
foreach(var property in properties)
{
var value = property.GetValue(item, null);
if(value != null)
((IDictionary<string, object>)result).Add(property.Name, value);
}
return (IDictionary<string, object>)result;
}).GroupBy(prop => prop.Key, prop => prop.Value)
.Select(g =>
{
var result = new ExpandoObject();
((IDictionary<string, object>)result).Add(g.Key, g.ToArray());
return result;
})
.ToList()
这不是最优雅的代码,但它应该完成工作。