性能(JAVA)~ 循环中的字符串连接,带有前置和附加
Posted
技术标签:
【中文标题】性能(JAVA)~ 循环中的字符串连接,带有前置和附加【英文标题】:Performance (JAVA) ~ String concatenation in a loop with prepending and appending 【发布时间】:2017-04-19 08:05:46 【问题描述】:我遇到了性能问题。有没有人有更快/更好的解决方案来执行以下操作:
String main = "";
for (String proposition : propositions)
if (main.length() == 0)
main = proposition;
else
main = "|(" + proposition + "," + main + ")";
我知道 concat 和 stringbuilder 更快,但我不知道如何使用这些方法。因为下面这行代码:
main = "|(" + proposition + "," + main + ")";
提前致谢!
【问题讨论】:
你想达到什么目的?您的预期结果是什么? @AndrewTobilko 他想要一种更快的方法来提高性能。 您是否尝试过插入 StringBuilder? docs.oracle.com/javase/7/docs/api/java/lang/… 或在迭代之前反转propositions
,那是否只允许您追加?
proposition.length()
可以为零吗?向后循环可能更容易使用StringBuilder
。
@lmiguelvargasf:赞成者可能会赞成,因为转换此代码以使用更有效的字符串构建形式实际上并非易事,因为混合了前置和附加。
【参考方案1】:
所以据我所知,这里有 3 个问题:
-
值主要附加到字符串中。
为每个值附加一个字符。
如果只存在一个值,则不应附加或前置任何值。
对于 2 个或更多项目,第 0 个项目的处理方式不同:
0:""
1:"A"
2:"|(B,A)"
3:"|(C,|(B,A))"
做一些改变可以更快:
-
反转算法,这意味着大部分工作都涉及追加,允许您使用 StringBuilders。
计算关闭
)
的次数并在循环结束后追加。
列表中 0 或 1 项的特殊情况。
通过这些更改,算法应该能够使用 StringBuilder 并且速度更快。
尝试一种算法:
int length = propositions.size();
if (length == 0)
main = "";
else
StringBuilder sb = new StringBuilder();
int nestingDepth = 0;
// Reverse loop, ignoring 0th element due to special case
for (int i = length - 1; i > 0; i--)
sb.append("|(").append(propositions.get(i)).append(',');
nestingDepth++;
// Append last element due to special casing
sb.append(propositions.get(0));
for (int i = 0; i < nestingDepth; i++)
sb.append(')');
main = sb.toString();
我相信这应该会产生正确的结果,但它应该给出正确的想法。
【讨论】:
他不需要逆算法。StringBuilder.insert()
存在。
@EJP:但是使用insert
会失败,因为您不会对二次运行时做任何事情。
@EJP 插入需要移动所有先前的输入,它可能涉及与原始代码一样多的内存改组。
insert 可能需要移动输入,但仍然比创建所有这些字符串的原始速度更快
另一种选择是使用ArrayDeque
,它是一个循环结构,在开头插入的速度与结尾一样快。最后你可以加入所有的字符串。【参考方案2】:
问题是您在进行时要预先添加和附加到字符串。 String 和 StringBuilder 不能很好地处理这个问题(并给出二次性能)。但是您可以使用支持在开始和结束时插入的出队来存储所有片段。最后你可以加入出队中的位。
ArrayDeque bits = new ArrayDeque();
for (String proposition : propositions)
if (bits.size() == 0)
bits.push(proposition);
else
// Add prefix
main.offerFirst("|(" + proposition + "," );
// Add suffix
main.push(")");
StringBuilder sb = new StringBuilder();
for( String s : bits)
sb.append(s);
main = sb.toString();
【讨论】:
我要试试这个方法,谢谢大家的回复。【参考方案3】:假设这是一个propositions
的数组,您可以先将数组中String
(s) 的长度相加。为您的其他字符添加 4,并减去 4,因为您没有在第一个元素上使用这些分隔符。这应该是您的输出的 完美 大小(这是可选的,因为 StringBuilder
是动态调整大小的)。接下来,构造一个StringBuilder
。添加第一个元素。所有后续元素都遵循相同的模式,因此使用传统的for
简化了循环。类似的,
int len = Stream.of(propositions).mapToInt(s -> s.length() + 4).sum() - 4;
StringBuilder sb = new StringBuilder(len); // <-- len is optional
sb.append(propositions[0]);
for (int i = 1; i < propositions.length; i++)
sb.insert(0, ",").insert(0, propositions[i]).insert(0, "|(").append(")");
System.out.println(sb);
【讨论】:
我要试试这个方法,谢谢大家的回复。以上是关于性能(JAVA)~ 循环中的字符串连接,带有前置和附加的主要内容,如果未能解决你的问题,请参考以下文章
带有连接和group by子句的选择查询中的MySQL性能问题