[英]How can I merge the results of a group by Linq-to-XML query?
我正在尝试构造一个执行以下步骤的Linq-to-XML查询:
到目前为止,我具有使用以下代码的前两个步骤。 请注意,MyGroupByKeyFunction的编写方式可确保(除其他事项外)每个组中的所有元素都具有相同的深度(这就是orderby起作用的原因)。
var groups =
from e in doc.Root.Descendants()
group e by MyGroupByKeyFunction(e) into g
orderby g.First().Ancestors().Count() descending
select new {
agg = g.Aggregate(new List<XElement>(), (list, el) => {
list.Add(el);
return list;
}).Distinct(new MyCustomXElementEqualityComparer()),
items = g,
target = g.Last().Parent
};
最后两个步骤是我陷入困境的地方。 我尝试了以下方法,但是它并没有按照我想要的方式工作。
foreach (var group in groups)
{
group.items.Remove();
foreach (var item in group.merge)
{
group.target.Add(item);
}
}
group.items中的元素已成功删除并填充了目标,但我也希望在对group.items.Remove()的调用导致清空父元素的情况下,删除group.items中元素的父元素。 因此,我尝试用以下命令替换该行:
foreach (var delete in group.items)
{
if (delete.Parent.Elements().Count() == 1)
delete.Parent.Remove();
else
delete.Remove();
}
问题在于,此循环结果的连续迭代会导致NullReferenceException,因为父元素可能作为项目存在于原始查询结果的另一个组中! 当然,这会导致delete.Parent为null,因为它先前已与XML树分离。
我该如何解决这个问题?
更新资料
根据Falanor的建议,我尝试将代码修改为以下内容。 但是,这导致XDocument的最终结果仅包含根元素。 我不知道为什么会这样。 有什么想法或更好的解决方案吗?
HashSet<XElement> removed = new HashSet<XElement>();
foreach (var group in groups)
{
removed.UnionWith(group.items.Select(el => el.Parent).Where(el => !el.Parent.Equals(group.target)));
group.items.Remove();
foreach (var item in group.merge)
{
if (!removed.Contains(item))
group.target.Add(item);
}
}
removed.Where(el => el.Parent != null).Remove();
事实证明,Falanor的想法是正确的,我在编写导致其无法使用的解决方案的方式时出现了一个小错误。 对UnionWith的方法调用应该是:
removed.UnionWith(group.items.Select(el => el.Parent).Where(el => !el.Equals(group.target)));
注意错误在where子句中。
此外,对于任何有兴趣的人,我意识到我可以通过在初始查询中添加以下“ where”子句(恰好在最终的“ select”语句之前)来大大减少代码的执行时间:
where g.Select(p => p.Parent).Distinct().Count() > 1
这将导致查询仅返回属于不同父级的元素的分组。 只是为了透视起见,我针对我的代码的XML文件返回了200,000多个分组。 加上附加的“ where”子句,分组数量下降到约150个! 最终结果是相同的。
也许删除父母(以及孩子们)这样做?
foreach (var group in groups)
{
if(group.Parent.Elements().Count() == 1)
group.Parent.Remove();
else
group.items.Remove();
foreach (var item in group.merge)
{
group.target.Add(item);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.