java: use StringBuilder para inserir no início


95

Eu só poderia fazer isso com String, por exemplo:

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

Existe uma maneira de fazer isso com StringBuilder? Obrigado.

Respostas:


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

Aviso: isso vai contra o propósitoStringBuilder , mas cumpre o que você pediu.


Melhor técnica (embora ainda não seja ideal):

  1. Inverta cada corda que deseja inserir.
  2. Anexe cada string a um StringBuilder.
  3. Inverta a inteira StringBuilder quando você está feito.

Isso transformará uma solução O ( n ²) em O ( n ).


2
... já que faz AbstractStringBuildermover todos os conteúdos além do índice de inserção para encontrar espaço para os inseridos. No entanto, esse é um detalhe de implementação, não de princípio.
entonio

1
@entonio: Sim, mas é um detalhe muito crítico . :)
user541686

1
Entendo, parece que eu não deveria estar usando StringBuilder então, muito
obrigado

@ user685275: Sim, se você precisa da inserção reversa, então você realmente precisa de algo que possa ser inserido no início da string. Eu acho que a solução mais fácil é a técnica acima (invertendo as coisas duas vezes), embora você provavelmente pudesse fazer uma classe melhor com arrays char (pode querer dar uma olhada em "deque" s).
user541686

1
@rogerdpack: Eu diria que esse é o mecanismo, não o propósito. O objetivo é ser assintoticamente mais rápido do que a manipulação de cordas, o que não acontecerá se você usar de forma errada.
user541686 de

32

você pode usar strbuilder.insert(0,i);


2
Por que recebeu tantas curtidas! A classe não está definida corretamente - apenas a assinatura da chamada do método!
JGFMK

14

Talvez eu esteja faltando alguma coisa, mas você quer terminar com uma String parecida com esta "999897969594...543210", correto?

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

Estranho, esse post não teve muitos votos ao fornecer a solução por meio da manipulação inteligente do loop,
nom-mon-ir

1
@ nom-mon-ir ele acabou de inverter a corda. Não responde como anexar à esquerda.
Raymond Chenon

Alcança o efeito desejado.
Speck de

Acho que pode haver casos em que você pode usar essa abordagem em vez de tentar hackear uma maneira de fazer a inserção no início que usa o verdadeiro potencial do StringBuilder. De qualquer forma, há casos em que você não pode inverter o loop, então você também precisa das outras respostas.
PhoneixS

7

Como uma solução alternativa, você pode usar uma estrutura LIFO (como uma pilha) para armazenar todas as strings e, quando terminar, basta retirá-las e colocá-las no StringBuilder. Ele inverte naturalmente a ordem dos itens (strings) colocados nele.

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
ArrayDequedeve ser usado em vez de Stack. "Um conjunto mais completo e consistente de operações de pilha LIFO é fornecido pela interface {@link Deque} e suas implementações, que devem ser usadas em preferência a esta classe."
Lua

5

Este thread é bastante antigo, mas você também pode pensar em uma solução recursiva passando o StringBuilder para preencher. Isso permite evitar qualquer processamento reverso, etc. Basta projetar sua iteração com uma recursão e decidir cuidadosamente por uma condição de saída.

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

Eu tive um requisito semelhante quando tropecei neste post. Eu queria uma maneira rápida de construir uma String que pudesse crescer de ambos os lados, ou seja. adicione novas letras na frente e no verso arbitrariamente. Sei que este é um post antigo, mas me inspirou a experimentar algumas maneiras de criar strings e pensei em compartilhar minhas descobertas. Também estou usando algumas construções Java 8 nisso, que poderiam ter otimizado a velocidade nos casos 4 e 5.

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

A essência acima contém o código detalhado que qualquer pessoa pode executar. Eu peguei algumas maneiras de aumentar as cordas nisso; 1) Anexar ao StringBuilder, 2) Inserir na frente do StringBuilder como mostrado por @Mehrdad, 3) Inserir parcialmente da frente, bem como no final do StringBuilder, 4) Usar uma lista para anexar do final, 5) Usar um Deque para anexar pela frente.

// 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(""));

Vou me concentrar nos casos de acréscimo frontal apenas, ou seja. caso 2 e caso 5. A implementação de StringBuilder internamente decide como o buffer interno cresce, que além de mover todo o buffer da esquerda para a direita no caso de acréscimo frontal, limita a velocidade. Enquanto o tempo gasto ao inserir diretamente na frente do StringBuilder cresce para valores realmente altos, como mostrado por @Mehrdad, se a necessidade é ter apenas strings de comprimento inferior a 90 mil caracteres (o que ainda é muito), a inserção frontal irá construir uma String ao mesmo tempo que levaria para construir uma String do mesmo comprimento, acrescentando no final. O que estou dizendo é que a penalidade de tempo realmente chuta e é enorme, mas apenas quando você tem que construir cordas realmente grandes. Pode-se usar um deque e juntar as cordas no final, conforme mostrado no meu exemplo.

Na verdade, o desempenho do caso 2 é muito mais rápido do que o do caso 1, o que não pareço entender. Presumo que o crescimento do buffer interno em StringBuilder seria o mesmo no caso de acréscimo frontal e acréscimo posterior. Eu até configurei o heap mínimo para uma quantidade muito grande para evitar atraso no crescimento do heap, se isso tivesse ajudado. Talvez alguém que tenha um melhor entendimento possa comentar abaixo.


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
Bem-vindo ao stackoverflow. Inclua uma explicação sobre o que o código faz e como ele resolve o problema da pergunta.
bad_coder

1

Você pode usar o método de inserção com o deslocamento. como deslocamento definido como '0' significa que você está anexando à frente de seu StringBuilder.

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

NOTA : como o método de inserção aceita todos os tipos de primitivas, você pode usar para int, long, char [] etc.


0

E se:

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

OU

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

Mas com isso, você está fazendo a operação O (N ^ 2) em vez de O (N).

Snippet de documentos java:

Insere a representação de string do argumento Object nesta sequência de caracteres. O efeito geral é exatamente como se o segundo argumento fosse convertido em uma string pelo método String.valueOf(Object)e os caracteres dessa string fossem então inseridos nessa sequência de caracteres no deslocamento indicado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.