如何从平面 XDocument 进行 GroupJoin?
我有一个 XDocument,其片段类似于:
<前><代码><数据>; <行 ID="0" ParentId="-1"> <行 ID="1" ParentId="0"> <行 ID="2" ParentId="0"> <行 ID="3" ParentId="-1"> <行 ID="4" ParentId="3">
假设嵌套仅限于上面的示例。
我想创建一个数据结构 - IDictionary
。我似乎无法正确加入任何东西。到目前为止我所知道的是:
// get lists of data nodes
List<XElement> pRows = xData.Elements(XName.Get("Row"))
.Where(e => e.Attribute(XParentId).Value == "-1")
.Select(e => e)
.ToList();
List<XElement> cRows = xData.Elements(XName.Get("Row"))
.Where(e => e.Attribute(XParentId).Value != "-1")
.Select(e => e)
.ToList();
var dataSets = pRows.GroupJoin(cRows,
p => p,
c => c.Attribute(XParentId).Value,
(p, children) => new {
ParentID = p.Attribute(XId).Value,
Children = children.Select(c => c)
});
编译器正在抱怨:
方法的类型参数 'System.Linq.Enumerable.GroupJoin(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable, 系统.Func,系统.Func, System.Func,TResult>)' 无法从用法推断。尝试指定类型参数 明确地。
我按照 MSDN 使用 GroupJoin 中的示例进行操作。我不想使用 2 个列表 - 我更喜欢使用包含所有行的 List
的单个列表。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为 2 列表方法更干净,除非我会避免调用
ToList()
直到最后一步或真正需要列表时。你可以把它变成一个声明,但它会很长而且很难理解。要修复您的查询,您需要将
pRows
的外部键选择器从p => 更改为p
到p => p.Attribute(XId).Value
,这是实际的ID。目前它选择整个元素,这不能与c => 进行比较。 c.Attribute(XParentId).Value
因为它们是不同的类型。更新后的查询将是:为了避免使用 2 个列表,您可以修改上面的查询,并将
pRows
和cRows
替换为它们各自的查询,但这使得查询变得又长又难。眼睛。在这种特殊情况下,我更喜欢使用查询语法来表达GroupJoin
,因为它比流畅的语法更容易阅读:如果您的实际问题有更多嵌套,LINQ 可能不是理想的解决方案。
I think the 2 list approach is cleaner, except I would avoid calling
ToList()
until the final step or when the list is really needed. You could turn it into one statement, but it would be long and harder to follow.To fix your query, you need to change the outer key selector for
pRows
fromp => p
top => p.Attribute(XId).Value
, which is the actual ID. Currently it selects the entire element, which cannot be compared toc => c.Attribute(XParentId).Value
since they are different types. The updated query would be:To avoid using 2 lists you could modify the query above and replace
pRows
andcRows
with their respective queries, but that makes it long and harder on the eyes. In this particular case I prefer expressing theGroupJoin
using query syntax since it is much easier to read than the fluent syntax:Should your real problem have more nesting, LINQ probably won't be the ideal solution.
首先,要使代码编译,您可能需要替换参数
p =>;
与GroupJoin
中的 pp =>; p.Attribute(XId).Value
选择用于比较的键。结果,您将获得一个对象为
IEnumerable
{ Row Id=1, Row Id=2 }IEnumerable
的 IEnumerable > { Row Id=4 }当然,你也可以更改
.Select(c => c)
返回一个List
仅包含 ID (.Select(c => c.Attribute(XId).Value).ToList()
),但您仍然缺少ParentID=-1 并且您没有字典。如果您想包含 ParentID=-1 并获得一个
Dictionary>
那么您可能想尝试这个(作为起点),它使用不同的方法:我希望这会有所帮助,或者可能为进一步研究提供一个起点。
旁注:正如您可能知道的,LINQ 使用延迟执行,因此您可能不希望在每一步都调用 ToList() 来节省执行时间(取决于总体量)数据时,偶尔使用
ToList()
可能是个好主意,因为它可能会在处理过程中节省内存,但这取决于实际数据)。First, to make your code compile you might want to replace the parameter
p => p
in theGroupJoin
withp => p.Attribute(XId).Value
which selects the key for comparison.As a result you will get an IEnumerable with objects
IEnumerable<XElement>
{ Row Id=1, Row Id=2 }IEnumerable<XElement>
{ Row Id=4 }Of course, you can also change the
.Select(c => c)
to return aList<string>
with just the IDs (.Select(c => c.Attribute(XId).Value).ToList()
), but you are still missing ParentID=-1 and you don't have a dictionary.If you want to include the ParentID=-1 and also get a
Dictionary<string,List<string>>
then you might want to try this (as a point to start from), which uses a different approach:I hope this helps, or maybe provides a starting point for further research.
One side note: as you might know, LINQ uses deferred execution so you might not want to call
ToList()
on every step to save execution time (depending on the overall amount of data, it might be a good idea to useToList()
anyway now and then because it might save memory during processing, but this depends on the real data).