我根据IEnumerable
构建字符串,并执行以下操作:
public string BuildString()
{
var enumerable = GetEnumerableFromSomewhere(); // actually an in parameter,
// but this way you don't have to care
// about the type :)
var interestingParts = enumerable.Select(v => v.TheInterestingStuff).ToArray();
stringBuilder.Append("This is it: ");
foreach(var part in interestingParts)
{
stringBuilder.AppendPart(part);
if (part != interestingParts.Last())
{
stringBuilder.Append(", ");
}
}
}
private static void AppendPart(this StringBuilder stringBuilder, InterestingPart part)
{
stringBuilder.Append("[");
stringBuilder.Append(part.Something");
stringBuilder.Append("]");
if (someCondition(part))
{
// this is in reality done in another extension method,
// similar to the else clause
stringBuilder.Append(" = @");
stringBuilder.Append(part.SomethingElse");
}
else
{
// this is also an extension method, similar to this one
// it casts the part to an IEnumerable, and iterates over
// it in much the same way as the outer method.
stringBuilder.AppendInFilter(part);
}
}
我对这个成语并不完全满意,但我正在努力制定更简洁的东西。
当然,这是更大的字符串构建操作的一部分(其中有几个类似于此的块,以及其间的其他内容) - 否则我可能会删除StringBuilder
并直接使用string.Join(", ", ...)
。
尽管如此,我最简单的尝试是为每个迭代器构建这样的结构:
stringBuilder.Append(string.Join(", ", propertyNames.Select(prop => "[" + prop + "]")));
但在这里我仍然使用+
连接字符串,这使得感觉StringBuilder
并没有真正贡献很多。
如何在保持高效的同时简化此代码?
答案 0 :(得分:2)
你可以替换它:
string.Join(", ", propertyNames.Select(prop => "[" + prop + "]"))
使用c#6字符串插值:
string.Join(", ", propertyNames.Select(prop => $"[{prop}]"))
在这两种情况下,区别仅在于语义并且它并不重要。字符串连接就像在你的情况下选择一样不是问题。编译器仍然只为它创建一个新字符串(而不是4,每个段一个,联合字符串第四个)。
全部放在一起:
var result = string.Join(", ", enumerable.Select(v => $"[{v.TheInterestingStuff}]"));
因为foreach
的主体更复杂,以适应字符串插值范围,你可以删除字符串的最后N个字符,如KooKiz建议的那样。
string separator = ", ";
foreach(var part in interestingParts)
{
stringBuilder.Append("[");
stringBuilder.Append(part);
stringBuilder.Append("]");
if (someCondition(part))
{
// Append more stuff
}
else
{
// Append other thingd
}
stringBuilder.Append(separator);
}
stringBuilder.Length = stringBuilder.Lenth - separator;
在任何情况下,我认为为了更好的封装,循环范围的内容应该位于一个单独的函数中,该函数将接收part
和separator
并将返回输出字符串。根据user734028
StringBuilder
的扩展方法
答案 1 :(得分:0)
汇总解决方案:
Making new env: CartPole-v0
You are calling 'step()' even though this environment has already returned done = True. You should always call 'reset()' once you receive 'done = True' -- any further steps are undefined behavior
序列化解决方案:
var answer = interestingParts.Select(v => "[" + v + "]").Aggregate((a, b) => a + ", " + b);
答案 2 :(得分:0)
Aggregate
使用StringBuilder
扩展名方法
如果您的集合很大,那么将更有效地连接字符串
var builder = new StringBuilder();
list.Aggregate(builder, (sb, person) =>
{
sb.Append(",");
sb.Append("[");
sb.Append(person.Name);
sb.Append("]");
return sb;
});
builder.Remove(0, 1); // Remove first comma
由于纯foreach
总是比LINQ
更高效,所以只需更改分隔符逗号的逻辑
var builder = new StringBuilder();
foreach(var part in enumerable.Select(v => v.TheInterestingStuff))
{
builder.Append(", ");
builder.Append("[");
builder.Append(part);
builder.Append("]");
}
builder.Remove(0, 2); //Remove first comma and space
答案 3 :(得分:0)
代码:
public string BuildString()
{
var enumerable = GetEnumerableFromSomewhere();
var interestingParts = enumerable.Select(v => v.TheInterestingStuff).ToArray();
stringBuilder.Append("This is it: ");
foreach(var part in interestingParts)
{
stringBuilder.AppendPart(part)
}
if (stringBuilder.Length>0)
stringBuilder.Length--;
}
private static void AppendPart(this StringBuilder stringBuilder, InterestingPart part)
{
if (someCondition(part))
{
stringBuilder.Append(string.Format("[{0}] = @{0}", part.Something));
}
else
{
stringBuilder.Append(string.Format("[{0}]", part.Something));
stringBuilder.AppendInFilter(part); //
}
}
现在IMO好多了。
现在进行一些讨论,让它变得非常快。我们可以使用Parallel.For。但你会想(如果你认为)Append都发生在一个可共享的资源上,也就是StringBuilder,然后你必须把它锁定到Append to it,效率不高!好吧,如果我们可以说外部函数中for循环的每次迭代创建一个单独的字符串工件,那么我们可以有一个字符串数组,在Parallel开始之前分配给interestingPart的计数,并且每个索引都是Parallel for将其字符串存储到其各自的索引中。
类似的东西:
string[] iteration_buckets = new string[interestingParts.Length];
System.Threading.Tasks.Parallel.For(0, interestingParts.Length,
(index) =>
{
iteration_buckets[index] = AppendPart(interestingParts[index]);
});
你的函数AppendPart必须进行调整,使其成为非扩展名,只取一个字符串并返回一个字符串。 循环结束后你可以做一个string.Join得到一个字符串,这也是你可能用stringBuilder.ToString()做的。