Linq 排除子项中的列
Linq Exclude columns in children
我正在尝试以下操作:给定动态对象列表,使用提供的列列表执行 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 等)
您可以使用 ExpandoObject
class 仅存储每个项目的唯一属性并反映到 select 这些唯一属性。
这就是我设法在 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
到 return 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()
这不是最优雅的代码,但它应该可以完成工作。
我正在尝试以下操作:给定动态对象列表,使用提供的列列表执行 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 等)
您可以使用 ExpandoObject
class 仅存储每个项目的唯一属性并反映到 select 这些唯一属性。
这就是我设法在 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
到 return 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()
这不是最优雅的代码,但它应该可以完成工作。