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

94

Я мог сделать это только с помощью String, например:

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

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

user685275
источник

Ответы:

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

пользователь541686
источник
2
... поскольку он заставляет AbstractStringBuilderперемещать все содержимое за пределы индекса вставки, чтобы найти место для вставленных. Однако это деталь реализации, а не принцип.
entonio
1
@entonio: Конечно, но это очень важная деталь. :)
user541686 09
1
Понятно, похоже, тогда мне не следует использовать StringBuilder, большое спасибо
user685275, 09
@ user685275: Да, если вам нужна обратная вставка, вам действительно нужно что-то, что можно вставить в начало строки. Я думаю, что самое простое решение - это описанная выше техника (дважды поменять местами), хотя вы, вероятно, могли бы создать свой собственный класс с массивами char (возможно, захотите изучить "deque").
user541686 09
1
@rogerdpack: Я бы сказал, что это механизм, а не цель. Цель состоит в том, чтобы быть асимптотически быстрее, чем манипуляции со строками, чего не будет, если вы используете их неправильно.
user541686
32

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

храповой урод
источник
2
Почему это получило столько лайков! Класс определен неправильно - только подпись вызова метода!
JGFMK
13

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

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

В качестве альтернативного решения вы можете использовать структуру 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();
Василе Юрески
источник
4
ArrayDequeследует использовать вместо Stack. «Более полный и последовательный набор операций стека LIFO обеспечивается интерфейсом {@link Deque} и его реализациями, которые следует использовать вместо этого класса»,
Луна,
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));
        }
    }
}
Бенджамин
источник
3

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

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

Сиддхарт Вагл
источник
1
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
Суреш Бабу Гарин
источник
1
Добро пожаловать в stackoverflow. Пожалуйста, включите в вопрос объяснение того, что делает код и как он решает проблему.
bad_coder
1

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

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

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

сачий
источник
0

Как насчет:

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

Пытаюсь
источник