【问题标题】:java: use StringBuilder to insert at the beginningjava:使用StringBuilder在开头插入
【发布时间】:2020-08-06 03:30:05
【问题描述】:

我只能用String来做这个,例如:

String str="";
for(int i=0;i<100;i++){
    str=i+str;
}

有没有办法通过 StringBuilder 实现这一点?谢谢。

【问题讨论】:

    标签: java string insert append stringbuilder


    【解决方案1】:
    StringBuilder sb = new StringBuilder();
    for(int i=0;i<100;i++){
        sb.insert(0, Integer.toString(i));
    }
    

    警告: 它违背了StringBuilder的目的,但它确实按照你的要求行事。


    更好的技术(虽然仍然不理想):

    1. 反转每个要插入的字符串。
    2. 追加每个字符串到StringBuilder
    3. 完成后将整个 StringBuilder 反转。

    这会将 O(n²) 解变成 O(n)。

    【讨论】:

    • ...因为它使AbstractStringBuilder 将所有内容移动到插入索引之外,以便为插入的内容找到空间。然而,这是一个实现细节,而不是一个原则。
    • @entonio:确实,但这是一个非常关键的细节。 :)
    • 我明白了,看来我不应该使用 StringBuilder,非常感谢
    • @user685275:是的,如果您需要向后插入,那么您确实需要可以在字符串开头插入的东西。我认为最简单的解决方案是上面的技术(将事情反转两次),尽管您可能可以使用 char 数组创建一个更好的类(可能想研究“deque”)。
    • @rogerdpack:我想说这是机制,而不是目的。目的是渐近地比字符串操作更快,如果你用错了就不会了。
    【解决方案2】:

    你可以使用strbuilder.insert(0,i);

    【讨论】:

    • 为什么会有这么多赞!该类未正确定义 - 只有方法调用的签名!
    【解决方案3】:

    也许我遗漏了一些东西,但你想以这样的字符串结束,"999897969594...543210",对吗?

    StringBuilder sb = new StringBuilder();
    for(int i=99;i>=0;i--){
        sb.append(String.valueOf(i));
    }
    

    【讨论】:

    • 奇怪的是,这篇文章在通过巧妙地操纵循环提供解决方案时没有获得太多投票,
    • @nom-mon-ir 他只是在反转字符串。它没有回答如何在左侧追加。
    • 达到想要的效果。
    • 我认为在某些情况下,您可以使用这种方法,而不是尝试破解一种方法来在开头使用 StringBuilder 的真正潜力进行插入。无论如何,在某些情况下您无法反转循环,因此您还需要其他答案。
    【解决方案4】:

    作为替代解决方案,您可以使用 LIFO 结构(如堆栈)来存储所有字符串,完成后只需将它们全部取出并放入 StringBuilder 中。它自然会颠倒放置其中的项目(字符串)的顺序。

    Stack<String> textStack = new Stack<String>();
    // push the strings to the stack
    while(!isReadingTextDone()) {
        String text = readText();
        textStack.push(text);
    }
    // pop the strings and add to the text builder
    String builder = new StringBuilder(); 
    while (!textStack.empty()) {
          builder.append(textStack.pop());
    }
    // get the final string
    String finalText =  builder.toString();
    

    【讨论】:

    • ArrayDeque 应该被使用而不是Stack。 “{@link Deque} 接口及其实现提供了一组更完整和一致的 LIFO 堆栈操作,应优先使用此类。”
    【解决方案5】:

    这个线程很老了,但你也可以考虑一个递归的解决方案,传递 StringBuilder 来填充。这样可以防止任何反向处理等。只需要使用递归设计迭代并仔细决定退出条件。

    public class Test {
    
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder();
            doRecursive(sb, 100, 0);
            System.out.println(sb.toString());
        }
    
        public static void doRecursive(StringBuilder sb, int limit, int index) {
            if (index < limit) {
                doRecursive(sb, limit, index + 1);
                sb.append(Integer.toString(index));
            }
        }
    }
    

    【讨论】:

      【解决方案6】:

      当我偶然发现这篇文章时,我也有类似的要求。我想要一种快速的方法来构建一个可以从两边增长的字符串,即。在正面和背面任意添加新字母。我知道这是一篇旧帖子,但它启发了我尝试几种创建字符串的方法,我想我会分享我的发现。我也在其中使用了一些 Java 8 结构,这可以优化案例 4 和 5 的速度。

      https://gist.github.com/SidWagz/e41e836dec65ff24f78afdf8669e6420

      上面的 Gist 包含任何人都可以运行的详细代码。 我采取了几种方法来增加字符串; 1) 追加到 StringBuilder,2) 插入到 StringBuilder 的前面,如 @Mehrdad 所示,3) 从 StringBuilder 的前面和末尾部分插入,4) 使用列表从末尾追加,5) 使用双端队列从前面追加。

      // Case 2    
      StringBuilder build3 = new StringBuilder();
      IntStream.range(0, MAX_STR)
                          .sequential()
                          .forEach(i -> {
                              if (i%2 == 0) build3.append(Integer.toString(i)); else build3.insert(0, Integer.toString(i));
                          });
      String build3Out = build3.toString();
      
      
      //Case 5
      Deque<String> deque = new ArrayDeque<>();
      IntStream.range(0, MAX_STR)
                      .sequential()
                      .forEach(i -> {
                          if (i%2 == 0) deque.addLast(Integer.toString(i)); else deque.addFirst(Integer.toString(i));
                      });
      
      String dequeOut = deque.stream().collect(Collectors.joining(""));
      

      我将专注于前面仅附加的情况,即。案例 2 和案例 5。 StringBuilder 的实现在内部决定了内部缓冲区的增长方式,除了在前面附加的情况下从左到右移动所有缓冲区之外,还限制了速度。虽然直接插入到 StringBuilder 前面所花费的时间会增长到非常高的值,如@Mehrdad 所示,如果只需要长度小于 90k 个字符的字符串(这仍然很多),前面插入将构建一个字符串的时间与通过在末尾追加构建一个相同长度的字符串所需的时间相同。我要说的是,时间惩罚确实很重要,而且是巨大的,但只有当你必须建立非常大的弦时。如我的示例所示,可以使用双端队列并在末尾加入字符串。但是 StringBuilder 更易于阅读和编码,而且对于较小的字符串,惩罚并不重要。

      其实case 2 的性能比case 1 快很多,我好像不太明白。我假设 StringBuilder 中内部缓冲区的增长在前追加和后追加的情况下是相同的。我什至将最小堆设置为非常大的数量以避免堆增长延迟,如果这会起作用的话。也许有更好理解的人可以在下面发表评论。

      【讨论】:

        【解决方案7】:

        您可以使用带有偏移量的插入方法。 因为偏移量设置为 '0' 意味着您要附加到 StringBuilder 的前面。

        StringBuilder sb = new StringBuilder();
        for(int i=0;i<100;i++){
            sb.insert(0,i);
        }
        

        注意: 由于 insert 方法接受所有类型的原语,您可以使用 int、long、char[] 等。

        【讨论】:

          【解决方案8】:
          Difference Between String, StringBuilder And StringBuffer Classes
          String
          String is immutable ( once created can not be changed )object. The object created as a
          String is stored in the Constant String Pool.
          Every immutable object in Java is thread-safe, which implies String is also thread-safe. String
          can not be used by two threads simultaneously.
          String once assigned can not be changed.
          StringBuffer
          StringBuffer is mutable means one can change the value of the object. The object created
          through StringBuffer is stored in the heap. StringBuffer has the same methods as the
          StringBuilder , but each method in StringBuffer is synchronized that is StringBuffer is thread
          safe .
          Due to this, it does not allow two threads to simultaneously access the same method. Each
          method can be accessed by one thread at a time.
          But being thread-safe has disadvantages too as the performance of the StringBuffer hits due
          to thread-safe property. Thus StringBuilder is faster than the StringBuffer when calling the
          same methods of each class.
          String Buffer can be converted to the string by using
          toString() method.
          
              StringBuffer demo1 = new StringBuffer("Hello") ;
          
          // The above object stored in heap and its value can be changed.
          /
          // Above statement is right as it modifies the value which is allowed in the StringBuffer
          StringBuilder
          StringBuilder is the same as the StringBuffer, that is it stores the object in heap and it can also
          be modified. The main difference between the StringBuffer and StringBuilder is
          that StringBuilder is also not thread-safe.
          StringBuilder is fast as it is not thread-safe.
          /
          // The above object is stored in the heap and its value can be modified
          /
          // Above statement is right as it modifies the value which is allowed in the StringBuilder
          

          【讨论】:

          • 欢迎来到stackoverflow。请说明代码的作用以及它如何解决问题中的问题。
          【解决方案9】:

          怎么样:

          StringBuilder builder = new StringBuilder();
          for(int i=99;i>=0;i--){
              builder.append(Integer.toString(i));
          }
          builder.toString();
          

          StringBuilder builder = new StringBuilder();
          for(int i=0;i<100;i++){
            builder.insert(0, Integer.toString(i));
          }
          builder.toString();
          

          但是有了这个,你的操作是 O(N^2) 而不是 O(N)。

          来自 java 文档的片段:

          将 Object 参数的字符串表示形式插入 this 字符序列。整体效果和第二个一模一样 该方法将参数转换为字符串 String.valueOf(Object),然后那个字符串的字符是 在指定的偏移量处插入到此字符序列中。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-23
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多