java: use StringBuilder para insertar al principio


94

Solo pude hacer esto con String, por ejemplo:

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

¿Hay alguna forma de lograr esto con StringBuilder? Gracias.

Respuestas:


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

Advertencia: frustra el propósito deStringBuilder , pero hace lo que pediste.


Mejor técnica (aunque todavía no es la ideal):

  1. Invierta cada cuerda que desee insertar.
  2. Agregue cada cuerda a un StringBuilder.
  3. Invierta todo StringBuilder cuando haya terminado.

Esto convertirá una solución de O ( n ²) en O ( n ).


2
... ya que hace AbstractStringBuildermover todos los contenidos más allá del índice de inserción para encontrar espacio para los insertados. Sin embargo, ese es un detalle de implementación, no uno de principio.
entonio

1
@entonio: De hecho, pero es un detalle muy crítico . :)
user541686

1
Ya veo, parece que no debería usar StringBuilder entonces, muchas gracias
user685275

@ user685275: Sí, si necesita una inserción hacia atrás, entonces realmente necesita algo que pueda insertar al principio de la cadena. Creo que la solución más fácil es la técnica anterior (invertir las cosas dos veces), aunque probablemente podría hacer una mejor clase propia con matrices de caracteres (es posible que desee buscar en "deque").
user541686

1
@rogerdpack: Yo diría que ese es el mecanismo, no el propósito. El propósito es ser asintóticamente más rápido que la manipulación de cadenas, lo cual no será así si lo usas mal.
user541686

32

puedes usar strbuilder.insert(0,i);


2
¿Por qué esto obtuvo tantos Me gusta? La clase no está definida correctamente, ¡solo la firma de la llamada al método!
JGFMK

13

Tal vez me esté perdiendo algo, pero quieres terminar con un String que se vea así "999897969594...543210", ¿correcto?

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

Extraño este post no hay nada de votación mientras que proporciona la solución mediante la manipulación inteligente del bucle,
nom-mon-IR

1
@ nom-mon-ir él acaba de invertir la cadena. No responde cómo agregar a la izquierda.
Raymond Chenon

Consigue el efecto deseado.
Speck

Creo que podría haber casos en los que pueda usar este enfoque en lugar de intentar piratear una forma de hacer la inserción al principio que use el verdadero potencial de StringBuilder. De todos modos, hay casos en los que no puede revertir el ciclo, por lo que también necesita las otras respuestas.
PhoneixS

7

Como solución alternativa, puede usar una estructura LIFO (como una pila) para almacenar todas las cadenas y cuando haya terminado, simplemente sáquelas todas y colóquelas en StringBuilder. Naturalmente, invierte el orden de los elementos (cadenas) colocados en él.

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
ArrayDequedebe usarse en lugar de Stack. "La interfaz {@link Deque} y sus implementaciones proporcionan un conjunto más completo y coherente de operaciones de pila LIFO, que deben usarse con preferencia a esta clase"
Luna

5

Este hilo es bastante antiguo, pero también podría pensar en una solución recursiva pasando el StringBuilder para completar. Esto permite evitar cualquier procesamiento inverso, etc. Solo necesita diseñar su iteración con una recursividad y decidir cuidadosamente una condición de salida.

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

Tenía un requisito similar cuando me topé con esta publicación. Quería una forma rápida de construir una cadena que pueda crecer desde ambos lados, es decir. agregue nuevas letras en la parte delantera y trasera de forma arbitraria. Sé que esta es una publicación antigua, pero me inspiró a probar algunas formas de crear cadenas y pensé en compartir mis hallazgos. También estoy usando algunas construcciones de Java 8 en esto, que podrían haber optimizado la velocidad en los casos 4 y 5.

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

La esencia anterior tiene el código detallado que cualquiera puede ejecutar. Tomé algunas formas de hacer crecer las cuerdas en esto; 1) Adjuntar a StringBuilder, 2) Insertar al frente de StringBuilder como se muestra en @Mehrdad, 3) Insertar parcialmente desde el frente y el final del StringBuilder, 4) Usar una lista para agregar desde el final, 5) Usar un Deque para añadir desde el 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(""));

Me centraré en los casos adjuntos al frente, es decir. caso 2 y caso 5. La implementación de StringBuilder decide internamente cómo crece el búfer interno, lo que además de mover todo el búfer de izquierda a derecha en caso de adición frontal limita la velocidad. Si bien el tiempo que se tarda en insertar directamente al frente del StringBuilder crece a valores realmente altos, como lo muestra @Mehrdad, si solo se necesita tener cadenas de menos de 90k caracteres (que todavía es mucho), el inserto frontal construya una cadena en el mismo tiempo que se necesitaría para construir una cadena de la misma longitud agregando al final. Lo que estoy diciendo es que la penalización de tiempo de hecho patea y es enorme, pero solo cuando tienes que construir cuerdas realmente enormes. Se podría usar una deque y unir las cuerdas al final como se muestra en mi ejemplo.

En realidad, el rendimiento para el caso 2 es mucho más rápido que el del caso 1, que no parece entender. Supongo que el crecimiento del búfer interno en StringBuilder sería el mismo en el caso de la adición frontal y posterior. Incluso establecí el montón mínimo en una cantidad muy grande para evitar retrasos en el crecimiento del montón, si eso hubiera jugado un papel. Quizás alguien que tenga una mejor comprensión pueda comentar a continuación.


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
Bienvenido a stackoverflow. Incluya una explicación de lo que hace el código y cómo resuelve el problema en la pregunta.
bad_coder

1

Puede utilizar el método de inserción con el desplazamiento. como offset establecido en '0' significa que está agregando al frente de su StringBuilder.

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

NOTA : como el método de inserción acepta todos los tipos de primitivas, puede usar para int, long, char [], etc.


0

Qué tal si:

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

O

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

Pero con esto, estás haciendo la operación O (N ^ 2) en lugar de O (N).

Fragmento de documentos java:

Inserta la representación de cadena del argumento de objeto en esta secuencia de caracteres. El efecto general es exactamente como si el segundo argumento se convirtiera en una cadena mediante el método String.valueOf(Object), y los caracteres de esa cadena se insertaran en esta secuencia de caracteres en el desplazamiento indicado.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.