假设我有一个内存中的XElement,如下所示:
<ROOT>
<CHILD1 />
<CHILD1 />
<CHILD2 />
<CHILD2 />
<CHILD1 />
<CHILD1 />
<CHILD3 />
<CHILD3 />
</ROOT>
除最后一个节点外,必须删除所有CHILD1节点。
树有大约100万个节点&amp;其中70%是CHILD1节点。什么是及时删除这些未使用的节点的最有效方法?我尝试了以下方法:
List<XElement> remNodes = root.Elements("CHILD1").ToList();
remNodes.RemoveRange(0, remNodes.Length - 1)
还有旧的&amp;简单的方法:
XElement[] remNodes = root.Elements("CHILD1").ToArray();
for (i=0;i<remNodes.Length-1;i++) remNodes[i].Remove();
两个人花了太多时间才完成(约5个小时)。有更快的方法吗?
更新1
试图保存最后一个节点&amp;删除如下:
XElement savedNode = remNodes.Last();
savedNode.Save("to_file");
root.Elements("CHILD1").Remove();
但看起来时间是一样的。
更新2
最后,我最终及时完成了任务(不到1分钟)。我使用了一种将有效节点保存到文件的方法,然后删除整个树和&amp;使用保存的节点重新加载树。感谢@Matthew Haugen的想法。你介意添加你的答案吗?
感谢。
答案 0 :(得分:0)
尝试,
root.Elements("CHILD1").Reverse().Skip(1).Remove();
答案 1 :(得分:0)
我把它扔在了一起。 200000个子元素。不用太长时间,但我不太确定你有多少人试图合作。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string data = DummyData();
//DeleteNodes("child1", data);
DeleteNodes2("child1", data);
Console.ReadLine();
}
static void DeleteNodes(string node, string xml)
{
var values = new HashSet<string>();
var xmlDocument = XDocument.Parse(xml);
foreach (var n in xmlDocument.Root.Elements(node).ToList())
{
if (!values.Add((string)node))
n.Remove();
}
}
static void DeleteNodes2(string node, string xml)
{
var xmlDocument = XDocument.Parse(xml);
xmlDocument.Root
.Elements(node).GroupBy(g => g).SelectMany(f => f).Reverse().Skip(1).Remove();
//Test to see how many are left
var duplicates = xmlDocument.Root
.Elements(node).GroupBy(g => g).ToList();
}
static string DummyData()
{
Random r = new Random();
TextWriter w = new StringWriter();
var writer = new XmlTextWriter(w);
writer.Formatting = Formatting.Indented;
writer.WriteStartElement("root");
for (int i = 0; i < 200000; i++)
{
int rand = r.Next(3);
writer.WriteStartElement(string.Format("child{0}", rand.ToString()));
writer.WriteEndElement();
}
writer.WriteEndElement();
return w.ToString();
}
}
}
如果这确实更快,那么应该归功于Chuck。这只是他所建议的分歧。
答案 2 :(得分:0)
最后,我最终及时完成了任务(不到1分钟)。我使用了一种将有效节点保存到文件的方法,然后删除整个树和&amp;使用保存的节点重新加载树。