改进我选择具有唯一值的多个 XElements 来构建列表的方法
Improve on my way of selecting multiple XElements with unique values to build list
有没有办法改进这个?我觉得我有办法进行许多循环。
该代码从 XML 文档构建一个包含域名的字符串。根据 XML 文档中的域名是否在 hostSW(host Starts With)、hostCN(host Contains)或 hostEW(host EndsWith)元素中取决于我是否需要在末尾附加 *,开始+结束,或值的开始。
我使用哈希集来确保没有重复。
var startWith = xdoc.Root
.Descendants("Test")
.Elements("hostSW")
.ToList();
var contains = xdoc.Root
.Descendants("Test")
.Elements("hostCN")
.ToList();
var endsWith = xdoc.Root
.Descendants("Test")
.Elements("hostEW")
.ToList();
HashSet<string> domains = new HashSet<string>(); //use hashset so we don't duplicate results
foreach (XElement test in startWith)
{
domains.Add(test.Value.ToString() + "*");
}
foreach (XElement test in contains)
{
domains.Add("*" + test.Value.ToString() + "*");
}
foreach (XElement test in endsWith)
{
domains.Add("*" + test.Value.ToString());
}
string out = "BEGIN FILE ";
foreach (string domain in domains.ToArray())
{
out += "BEGIN DOMAIN ";
out += domain;
out += " END DOMAIN";
}
out += " END FILE;
return out;
XML 文件
<Tests>
<Test>
<hostSW>startsWith1</hostSW>
</Test>
<Test>
<hostSW>startsWith2</hostSW>
</Test>
<Test>
<hostCN>contains1</hostCN>
</Test>
<Test>
<hostEW>endsWith1</hostEW>
</Test>
</Tests>
假设 XML 结构像这样
<Root>
<Test>
<hostSW>startsWith1</hostSW>
</Test>
<Test>
<hostCN>contains1</hostCN>
</Test>
<Test>
<hostCN>contains2</hostCN>
</Test>
<Test>
<hostEW>endsWith1</hostEW>
</Test>
<Test>
<hostEW>endsWith2</hostEW>
</Test>
<Test>
<hostEW>endsWith3</hostEW>
</Test>
</Root>
我正确地得到了所有域,并且只用这段代码迭代了 6 次
// Loop each of the elements one time without filtering element name
foreach (var test in xDoc.Root.Descendants("Test").Elements())
{
// Switch on the name of the element.
switch (test.Name.LocalName)
{
case "hostSW": { domains.Add(test.Value + "*"); } break;
case "hostCN": { domains.Add("*" + test.Value + "*"); } break;
case "hostEW": { domains.Add("*" + test.Value); } break;
}
// For any other elements we iterate just do nothing
}
使用 Linq 来 XML 你可以:
var t = xml.Root.Descendants("Test")
.Elements()
.Where(x => x.Name == "hostSW" || x.Name == "hostCN" || x.Name == "hostEW")
.Select(x => (x.Name == "hostSW") ?
$"{x.Value}*"
:
(x.Name == "hostCN" ?
$"*{x.Value}*"
:
$"*{x.Value}"));
如果您的 <Test>
元素只包含 <hostSW>
、<hostCN>
或 <hostEW>
,那么您可以省略 Where
。
您尝试过使用 SelectSingleNode or the SelectNodes method with the XmlNode class 吗?我知道您正在尝试避免循环,但对于这种情况,只要我们知道根(父节点)保持不变,您就应该收到 O(n) 的时间复杂度。
您的 XML 文件似乎包含包含您需要的内部文本的节点,因此您可以这样做:
foreach (XmlNode node in xmlDoc.SelectNodes($"//Test/Test"))
{
switch (node.Name)
{
case "hostSW":
var newInnerText = node.InnerText + '*';
//do something
break;
case "hostCN":
var newInnerText = node.InnerText + '*';
//do something
break;
case "hostEW":
//do something
break;
default:
//do something
break;
}
}
这是另一种方法。这使用 LINQ Select
而不是循环,并使用 Dictionary
而不是 switch
/ 三叉树。它还利用了替代机制:在本例中我使用了 string.Format
,但包括 string.Replace
在内的许多其他机制同样适用。这完全取决于您要做什么。我通常追求合理的性能和经济的语法,通常在易于维护方面得分很高。
static Dictionary<string, string> dict = new Dictionary<string, string>() {
{ "hostSW", "{0}*" },
{ "hostCN", "*{0}*" },
{ "hostEW", "*{0}" },
};
static IEnumerable<string> WildcardStringsFromXML(XDocument xdoc)
{
return xdoc.Root.Descendants("Test").Elements()
.Select(item => string.Format(dict[item.Name.LocalName], item.Value));
}
有没有办法改进这个?我觉得我有办法进行许多循环。
该代码从 XML 文档构建一个包含域名的字符串。根据 XML 文档中的域名是否在 hostSW(host Starts With)、hostCN(host Contains)或 hostEW(host EndsWith)元素中取决于我是否需要在末尾附加 *,开始+结束,或值的开始。
我使用哈希集来确保没有重复。
var startWith = xdoc.Root
.Descendants("Test")
.Elements("hostSW")
.ToList();
var contains = xdoc.Root
.Descendants("Test")
.Elements("hostCN")
.ToList();
var endsWith = xdoc.Root
.Descendants("Test")
.Elements("hostEW")
.ToList();
HashSet<string> domains = new HashSet<string>(); //use hashset so we don't duplicate results
foreach (XElement test in startWith)
{
domains.Add(test.Value.ToString() + "*");
}
foreach (XElement test in contains)
{
domains.Add("*" + test.Value.ToString() + "*");
}
foreach (XElement test in endsWith)
{
domains.Add("*" + test.Value.ToString());
}
string out = "BEGIN FILE ";
foreach (string domain in domains.ToArray())
{
out += "BEGIN DOMAIN ";
out += domain;
out += " END DOMAIN";
}
out += " END FILE;
return out;
XML 文件
<Tests>
<Test>
<hostSW>startsWith1</hostSW>
</Test>
<Test>
<hostSW>startsWith2</hostSW>
</Test>
<Test>
<hostCN>contains1</hostCN>
</Test>
<Test>
<hostEW>endsWith1</hostEW>
</Test>
</Tests>
假设 XML 结构像这样
<Root>
<Test>
<hostSW>startsWith1</hostSW>
</Test>
<Test>
<hostCN>contains1</hostCN>
</Test>
<Test>
<hostCN>contains2</hostCN>
</Test>
<Test>
<hostEW>endsWith1</hostEW>
</Test>
<Test>
<hostEW>endsWith2</hostEW>
</Test>
<Test>
<hostEW>endsWith3</hostEW>
</Test>
</Root>
我正确地得到了所有域,并且只用这段代码迭代了 6 次
// Loop each of the elements one time without filtering element name
foreach (var test in xDoc.Root.Descendants("Test").Elements())
{
// Switch on the name of the element.
switch (test.Name.LocalName)
{
case "hostSW": { domains.Add(test.Value + "*"); } break;
case "hostCN": { domains.Add("*" + test.Value + "*"); } break;
case "hostEW": { domains.Add("*" + test.Value); } break;
}
// For any other elements we iterate just do nothing
}
使用 Linq 来 XML 你可以:
var t = xml.Root.Descendants("Test")
.Elements()
.Where(x => x.Name == "hostSW" || x.Name == "hostCN" || x.Name == "hostEW")
.Select(x => (x.Name == "hostSW") ?
$"{x.Value}*"
:
(x.Name == "hostCN" ?
$"*{x.Value}*"
:
$"*{x.Value}"));
如果您的 <Test>
元素只包含 <hostSW>
、<hostCN>
或 <hostEW>
,那么您可以省略 Where
。
您尝试过使用 SelectSingleNode or the SelectNodes method with the XmlNode class 吗?我知道您正在尝试避免循环,但对于这种情况,只要我们知道根(父节点)保持不变,您就应该收到 O(n) 的时间复杂度。
您的 XML 文件似乎包含包含您需要的内部文本的节点,因此您可以这样做:
foreach (XmlNode node in xmlDoc.SelectNodes($"//Test/Test"))
{
switch (node.Name)
{
case "hostSW":
var newInnerText = node.InnerText + '*';
//do something
break;
case "hostCN":
var newInnerText = node.InnerText + '*';
//do something
break;
case "hostEW":
//do something
break;
default:
//do something
break;
}
}
这是另一种方法。这使用 LINQ Select
而不是循环,并使用 Dictionary
而不是 switch
/ 三叉树。它还利用了替代机制:在本例中我使用了 string.Format
,但包括 string.Replace
在内的许多其他机制同样适用。这完全取决于您要做什么。我通常追求合理的性能和经济的语法,通常在易于维护方面得分很高。
static Dictionary<string, string> dict = new Dictionary<string, string>() {
{ "hostSW", "{0}*" },
{ "hostCN", "*{0}*" },
{ "hostEW", "*{0}" },
};
static IEnumerable<string> WildcardStringsFromXML(XDocument xdoc)
{
return xdoc.Root.Descendants("Test").Elements()
.Select(item => string.Format(dict[item.Name.LocalName], item.Value));
}