我可以用我当前正在做的方式建立一本字典,但我想知道是否有更好更快的方法。我试图使用LINQ SelecMany语句,但遇到了麻烦。
result_str = ""
def dictionary_iterator(results):
global result_str
for key, value in results.items():
if isinstance(value, dict):
result_str = result_str + key + ": \n \t"
dictionary_iterator(value)
else:
result_str = result_str + key + ": " + str(value) + "\n"
return result_str
回复会让孩子在里面(第0个元素),然后在里面会有孩子,等等。第二个for循环只有4个孩子,第四个将不得不更深入一步并得到孩子们。
答案 0 :(得分:16)
第一步:停止使用字典。我们已经有了一个数据结构,它将密集的,从零开始的整数范围映射到数据:List<T>
。重构:
static string GetServerInfo(Thing thing)
{
string serverInfo = "";
for (int j = 0; j < 4; j++)
{
if (j == 3)
{
var jthReplyChildren = thing.Children[j];
for (int k = 0; k < jthReplyChildren.Count; k++)
{
serverInfo += jthReplyChildren.Children[k].TextData; //+ "::";
}
break;
}
serverInfo += thing.Children[j].TextData + ":";
}
return serverInfo;
}
现在您的主要计划是:
List<string> slowLog = reply.Children[0].Children.Select(GetServerInfo).ToList();
现在我们已经消除了一个循环并将问题简化为使GetServerInfo
看起来不那么可怕。
展开外循环:
static string GetServerInfo(Thing thing)
{
string serverInfo = "";
serverInfo += thing.Children[0].TextData + ":";
serverInfo += thing.Children[1].TextData + ":";
serverInfo += thing.Children[2].TextData + ":";
var fourthChild = thing.Children[3];
for (int k = 0; k < fourthChild.Count; k++)
serverInfo += fourthChild.Children[k].TextData;
return serverInfo;
}
很好,现在我们已经到了一个循环。消除那个循环:
static string GetServerInfo(Thing thing)
{
string serverInfo = "";
serverInfo += thing.Children[0].TextData + ":";
serverInfo += thing.Children[1].TextData + ":";
serverInfo += thing.Children[2].TextData + ":";
serverInfo += string.Join("", thing.Children[3].Children.Select(x => x.TextData));
return serverInfo;
}
我们也可以为其他人使用Join:
static string GetServerInfo(Thing thing)
{
string firstThree = string.Join("", thing.Children.Take(3).Select( x => x.TextData + ":"));
string fourth = string.Join("", thing.Children[3].Children.Select(x => x.TextData));
return firstThree + fourth;
}
进一步减少:
static string GetServerInfo(Thing thing)
{
return
string.Join("", thing.Children.Take(3).Select(x => x.TextData + ":")) +
string.Join("", thing.Children[3].Children.Select(x => x.TextData));
}
使用箭头符号:
static string GetServerInfo(Thing thing) =>
string.Join("", thing.Children.Take(3).Select(x => x.TextData + ":")) +
string.Join("", thing.Children[3].Children.Select(x => x.TextData));
等一下,现在我们有一个lambda。重写原始网站:
List<string> slowLog = reply.Children[0].Children
.Select(thing =>
string.Join("", thing.Children.Take(3).Select(x => x.TextData + ":")) +
string.Join("", thing.Children[3].Children.Select(x => x.TextData)))
.ToList();
我们归结为一个声明。 没有循环;没有循环问题。逻辑非常明确地表达 - 取其中三个,将它们连接起来,等等等等,把它变成一个列表,完成。
我们可以走得更远吗?当然!我们可以在辅助函数中组合select和concatenate运算符,使我们的程序更加流利:
public static string SelectConcat<T>(this IEnumerable<T> items, Func<T, string> f) =>
string.Join("", items.Select(f));
现在我们的计划变成了
List<string> slowLog = reply.Children[0].Children
.Select(thing =>
thing.Children.Take(3).SelectConcat(x => x.TextData + ":") +
thing.Children[3].Children.SelectConcat(x => x.TextData))
.ToList();
现在非常清楚我们在做什么。
这里要说的是:目标不是让程序小;这不是代码高尔夫。 使代码读取更像其预期的语义。
您的原始代码使得它看起来像程序片段中最重要的是循环索引的值;看看有多少屏幕房地产专用于i,j和k。那些是机制。编写代码以强调含义。如果你的意思是“取前三个”,那么某处应该有Take(3)
,而不是for
循环。
我们如何从强调i,j和k值的初始程序到描述数据操作的程序?看看我在那里做了什么:我做了一系列小的,简单的重构,每个提高了抽象级别,使代码读取更像其预期的语义或消除不必要的“仪式”。
答案 1 :(得分:1)
我不是靠近IDE来测试它,但是我把它缩小了一点:
var replyChildren = reply.Children[0];
Dictionary<int, string> slowLog = new Dictionary<int, string>();
int i = 0;
foreach (var child in replyChildren.Children)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}:", child.Children[0].TextData);
sb.AppendFormat("{0}:", child.Children[1].TextData);
sb.AppendFormat("{0}:", child.Children[2].TextData);
sb.Append(string.Join(string.Empty, child.Children[3].Select(x => x.TextData));
slowLog.Add(i, sb.ToString());
i++;
}
我不完全了解您的要求,但正如评论中提到的@EricLippert,您可以使用List<string>
...
答案 2 :(得分:0)
第一步,让我们展开中间循环:
var replyChildren = reply.Children[0];
Dictionary<int, string> slowLog = new Dictionary<int, string>();
for (int i = 0; i < replyChildren.Children.Count(); i++)
{
var ithReplyChildren = replyChildren.Children[i];
serverInfo += ithReplyChildren.Children[0].TextData + ":";
serverInfo += ithReplyChildren.Children[1].TextData + ":";
serverInfo += ithReplyChildren.Children[2].TextData + ":";
var jthReplyChildren = ithReplyChildren.Children[3];
for (int k = 0; k < jthReplyChildren.Count; k++)
{
serverInfo += jthReplyChildren.Children[k].TextData;//+ "::";
}
slowLog.Add(i, serverInfo);
serverInfo = "";
}
然后我们将for()
替换为foreach(()
var replyChildren = reply.Children[0];
var slowLog = new Dictionary<int, string>();
int i = 0;
foreach(var ithReplyChildren in replyChildren.Children)
{
serverInfo += ithReplyChildren.Children[0].TextData + ":";
serverInfo += ithReplyChildren.Children[1].TextData + ":";
serverInfo += ithReplyChildren.Children[2].TextData + ":";
var jthReplyChildren = ithReplyChildren.Children[3];
foreach (var kthReplyChildren in jthReplyChildren.Children)
{
serverInfo += kthReplyChildren.TextData;//+ "::";
}
slowLog.Add(i++, serverInfo);
serverInfo = "";
}
然后迈克建议使用StringBuilder
var replyChildren = reply.Children[0];
var slowLog = new Dictionary<int, string>();
int i = 0;
foreach (var ithReplyChildren in replyChildren.Children)
{
var serverInfo = new StringBuilder();
serverInfo.Append(ithReplyChildren.Children[0].TextData);
serverInfo.Append(':');
serverInfo.Append(ithReplyChildren.Children[1].TextData);
serverInfo.Append(':');
serverInfo.Append(ithReplyChildren.Children[2].TextData);
serverInfo.Append(':');
var jthReplyChildren = ithReplyChildren.Children[3];
foreach (var kthReplyChildren in jthReplyChildren.Children)
{
serverInfo.Append(kthReplyChildren.TextData);
}
slowLog.Add(i++, serverInfo.ToString());
}