Java: используйте StringBuilder для вставки в начале

Я мог бы сделать это только со строкой, например:

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

Есть ли способ добиться этого с помощью StringBuilder? Спасибо.


person user685275    schedule 09.05.2011    source источник


Ответы (9)


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).

person user541686    schedule 09.05.2011
comment
... так как это заставляет AbstractStringBuilder перемещать все содержимое за пределы индекса вставки, чтобы найти место для вставленных. Однако это деталь реализации, а не принципиальная. - person entonio; 09.05.2011
comment
@entonio: Действительно, но это очень важная деталь. :) - person user541686; 09.05.2011
comment
Ясно, похоже, тогда мне не следует использовать StringBuilder, большое спасибо. - person user685275; 09.05.2011
comment
@ user685275: Да, если вам нужна обратная вставка, вам действительно нужно что-то, что может вставлять в начало строки. Я думаю, что самым простым решением является метод, описанный выше (дважды обращая все вспять), хотя вы, вероятно, могли бы создать свой собственный лучший класс с массивами символов (возможно, вы захотите изучить деки). - person user541686; 09.05.2011
comment
Другой вариант, когда условия правильные, — использовать связанный список с addFirst, а затем использовать Collectors.joining(...) для создания нужной строки. - person jorgeu; 10.05.2018
comment
@jorgeu: Трудно переоценить, насколько чрезвычайно редко бывает, чтобы связанный список был здесь лучшим выбором. - person user541686; 10.05.2018
comment
@Mehrdad, ты уверен, что знаешь, что делает построитель строк, когда ты добавляешь в начало? см. stackoverflow.com/questions/26170180/ - person jorgeu; 13.05.2018
comment
@jorgeu: Да. Я тоже не вижу ничего обратного в вашей ссылке. И посмотрите здесь. - person user541686; 13.05.2018
comment
@Mehrdad Я попробовал твою лучшую технику. вы должны добавить строку в обратном порядке. иначе, если вы добавите 01, вы получите 10 в окончательной строке - person Akhil Surapuram; 06.12.2018
comment
@AkhilSurapuram: Это то, что я упомянул в шаге №1, верно? - person user541686; 06.12.2018
comment
@Mehrdad извините, я хотел сказать, что вам также нужно перевернуть построитель строк, прежде чем вставлять перевернутые строки. - person Akhil Surapuram; 06.12.2018
comment
@AkhilSurapuram: Разве построитель строк изначально не пуст? - person user541686; 06.12.2018
comment
Хм... цель StringBuilder? Судя по javadocs, его цель - действовать как изменяемая строка, его типичное преимущество и использование - определенно избегать циклов добавления N ^ 2? В этом случае он повторно вводит цикл N ^ 2, но с размером ввода всего 100 все еще может быть приемлемо быстро, чтобы просто выполнять insert(0, ), в зависимости от того, как часто, возможно... :) - person rogerdpack; 20.02.2019
comment
@rogerdpack: я бы сказал, что это механизм, а не цель. Цель состоит в том, чтобы быть асимптотически быстрее, чем манипулирование строками, чего не будет, если вы используете его неправильно. - person user541686; 20.02.2019

вы можете использовать strbuilder.insert(0,i);

person ratchet freak    schedule 09.05.2011
comment
Почему это набрало столько лайков! Класс определен не правильно - только сигнатура вызова метода! - person JGFMK; 02.01.2020

Может быть, я что-то упускаю, но вы хотите получить строку, которая выглядит так, "999897969594...543210", правильно?

StringBuilder sb = new StringBuilder();
for(int i=99;i>=0;i--){
    sb.append(String.valueOf(i));
}
person Speck    schedule 09.05.2011
comment
Странно, что этот пост не получил большого количества голосов, хотя и предлагал решение путем умных манипуляций с циклом, - person nom-mon-ir; 17.11.2014
comment
@nom-mon-ir он просто переворачивает строку. Он не отвечает, как добавить слева. - person Raymond Chenon; 14.10.2015
comment
Достигает желаемого эффекта. - person Speck; 15.10.2015
comment
Я думаю, что могут быть случаи, когда вы можете использовать этот подход вместо того, чтобы пытаться взломать способ вставки в начале, который использует истинный потенциал StringBuilder. В любом случае, есть случаи, когда вы не можете изменить цикл, поэтому вам нужны и другие ответы. - person PhoneixS; 03.07.2018

В качестве альтернативного решения вы можете использовать структуру 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();
person Vasile Jureschi    schedule 08.01.2015
comment
ArrayDeque следует использовать вместо Stack. Более полный и согласованный набор операций стека LIFO предоставляется интерфейсом {@link Deque} и его реализациями, которые следует использовать вместо этого класса. - person Luna; 23.01.2016

Этот поток довольно старый, но вы также можете подумать о рекурсивном решении, передающем 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));
        }
    }
}
person Benjamin    schedule 04.01.2014

У меня было подобное требование, когда я наткнулся на этот пост. Мне нужен быстрый способ построить строку, которая может расти с обеих сторон, т.е. добавлять новые буквы как спереди, так и сзади произвольно. Я знаю, что это старый пост, но он вдохновил меня попробовать несколько способов создания строк, и я решил поделиться своими выводами. Я также использую здесь некоторые конструкции Java 8, которые могли бы оптимизировать скорость в случаях 4 и 5.

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

В Gist выше есть подробный код, который может запустить любой. Я использовал несколько способов выращивания струн в этом; 1) Добавить к StringBuilder, 2) Вставить в начало StringBuilder, как показано @Mehrdad, 3) Частично вставить как с начала, так и с конца StringBuilder, 4) Использование списка для добавления с конца, 5) Использование Deque для добавить с лицевой стороны.

// 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, если необходимо иметь только строки длиной менее 90 тыс. символов (что все еще много), передняя вставка будет построить строку за то же время, что и для создания строки той же длины, добавив в конце. Я говорю о том, что штраф за время действительно имеет значение и является огромным, но только тогда, когда вам нужно построить действительно огромные цепочки. Можно использовать дек и соединить строки в конце, как показано в моем примере. Но StringBuilder немного более интуитивно понятен для чтения и кодирования, и штраф не будет иметь значения для меньших строк.

На самом деле производительность для случая 2 намного выше, чем для случая 1, чего я, кажется, не понимаю. Я предполагаю, что рост внутреннего буфера в StringBuilder будет одинаковым в случае переднего и заднего добавления. Я даже установил очень большую минимальную кучу, чтобы избежать задержки в росте кучи, если бы это сыграло свою роль. Может быть, кто-то, у кого есть лучшее понимание, может прокомментировать ниже.

person Siddharth Wagle    schedule 30.12.2017

Вы можете использовать метод вставки со смещением. поскольку смещение, установленное на «0», означает, что вы добавляете к началу вашего StringBuilder.

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

ПРИМЕЧАНИЕ: поскольку метод вставки принимает все типы примитивов, вы можете использовать для int, long, char[] и т. д.

person sachyy    schedule 19.05.2020

Как насчет:

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

OR

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 в эту последовательность символов. Общий эффект такой же, как если бы второй аргумент был преобразован в строку методом String.valueOf(Object), а затем символы этой строки были вставлены в эту последовательность символов с указанным смещением.

person Trying    schedule 05.08.2020

person    schedule
comment
Добро пожаловать в stackoverflow.com. Пожалуйста, включите объяснение того, что делает код и как он решает проблему в вопросе. - person bad_coder; 28.03.2020