性能(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)~ 循环中的字符串连接,带有前置和附加的主要内容,如果未能解决你的问题,请参考以下文章

在Java中运行带有前置参数的exe [关闭]

带有连接和group by子句的选择查询中的MySQL性能问题

在带有许多 if 语句的 for 循环中使用 continue 时性能是不是有所提高?

Java 多线程与并发:前置知识

pgplsql 存储过程的性能?

带有相关子查询的 While 循环的 SQL Server 性能调整