java: gunakan StringBuilder untuk menyisipkan di awal


94

Saya hanya bisa melakukan ini dengan String, misalnya:

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

Apakah ada cara untuk mencapai ini dengan StringBuilder? Terima kasih.

Jawaban:


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

Peringatan: Itu mengalahkan tujuan dariStringBuilder , tapi itu melakukan apa yang Anda minta.


Teknik yang lebih baik (meski masih belum ideal):

  1. Balikkan setiap string yang ingin Anda sisipkan.
  2. Tambahkan setiap string ke a StringBuilder.
  3. Balikkan seluruhnya StringBuilder setelah Anda selesai.

Ini akan mengubah solusi O ( n ²) menjadi O ( n ).


2
... karena itu membuat AbstractStringBuildermemindahkan semua konten melewati indeks penyisipan untuk menemukan ruang untuk yang disisipkan. Namun, itu detail implementasi, bukan salah satu prinsip.
entonio

1
@entonio: Memang, tapi detailnya sangat kritis . :)
user541686

1
Begitu

@ user685275: Ya, jika Anda membutuhkan penyisipan mundur maka Anda benar-benar membutuhkan sesuatu yang dapat disisipkan di awal string. Saya pikir solusi termudah adalah teknik di atas (membalikkan dua kali), meskipun Anda mungkin bisa membuat kelas yang lebih baik dari Anda sendiri dengan array char (mungkin ingin melihat ke "deque").
pengguna541686

1
@rogerdpack: Menurut saya itulah mekanismenya, bukan tujuannya. Tujuannya adalah agar secara asimtotik lebih cepat daripada manipulasi string, yang tidak akan terjadi jika Anda salah menggunakannya.
pengguna541686

32

kamu bisa memakai strbuilder.insert(0,i);


2
Mengapa ini mendapatkan banyak suka! Kelas tidak didefinisikan dengan benar - hanya tanda tangan dari pemanggilan metode!
JGFMK

13

Mungkin saya melewatkan sesuatu tetapi Anda ingin berakhir dengan String yang terlihat seperti ini, bukan "999897969594...543210"?

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

Aneh posting ini tidak mendapatkan banyak voting sambil memberikan solusi dengan manipulasi cerdas dari loop,
nom-mon-ir

1
@ nom-mon-ir dia baru saja membalik String. Itu tidak menjawab bagaimana menambahkan di kiri.
Raymond Chenon

Mencapai efek yang diinginkan.
Speck

Saya pikir mungkin ada kasus di mana Anda dapat menggunakan pendekatan ini daripada mencoba meretas cara untuk melakukan penyisipan di awal yang menggunakan potensi sebenarnya dari StringBuilder. Bagaimanapun, ada kasus di mana Anda tidak dapat membalikkan pengulangan sehingga Anda juga membutuhkan jawaban lainnya.
PhoneixS

7

Sebagai solusi alternatif, Anda dapat menggunakan struktur LIFO (seperti tumpukan) untuk menyimpan semua string dan setelah selesai, keluarkan semuanya dan masukkan ke dalam StringBuilder. Ini secara alami membalik urutan item (string) yang ditempatkan di dalamnya.

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
ArrayDequeharus digunakan sebagai pengganti Stack. "Rangkaian operasi tumpukan LIFO yang lebih lengkap dan konsisten disediakan oleh antarmuka {@link Deque} dan implementasinya, yang harus digunakan sebagai preferensi untuk kelas ini."
Luna

5

Utas ini cukup lama, tetapi Anda juga dapat memikirkan solusi rekursif yang meneruskan StringBuilder untuk diisi. Hal ini memungkinkan untuk mencegah pemrosesan balik, dll. Hanya perlu merancang iterasi Anda dengan rekursi dan dengan hati-hati memutuskan untuk kondisi keluar.

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

Saya memiliki persyaratan serupa ketika saya menemukan posting ini. Saya ingin cara cepat untuk membangun String yang dapat tumbuh dari kedua sisi yaitu. tambahkan huruf baru di depan dan belakang secara sembarangan. Saya tahu ini adalah posting lama, tetapi itu menginspirasi saya untuk mencoba beberapa cara untuk membuat string dan saya pikir saya akan membagikan temuan saya. Saya juga menggunakan beberapa konstruksi Java 8 dalam hal ini, yang dapat mengoptimalkan kecepatan dalam kasus 4 dan 5.

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

Inti di atas memiliki kode rinci yang dapat dijalankan oleh siapa saja. Saya mengambil beberapa cara untuk mengembangkan tali dalam hal ini; 1) Tambahkan ke StringBuilder, 2) Sisipkan ke depan StringBuilder seperti yang ditunjukkan oleh @Mehrdad, 3) Sisipkan sebagian dari depan dan juga akhir StringBuilder, 4) Menggunakan daftar untuk ditambahkan dari akhir, 5) Menggunakan Deque ke tambahkan dari depan.

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

Saya akan fokus pada kasus hanya menambahkan depan yaitu. kasus 2 dan kasus 5. Implementasi StringBuilder secara internal memutuskan bagaimana buffer internal tumbuh, yang selain memindahkan semua buffer dari kiri ke kanan jika penambahan depan membatasi kecepatan. Sementara waktu yang dibutuhkan saat memasukkan langsung ke depan StringBuilder tumbuh menjadi nilai yang sangat tinggi, seperti yang ditunjukkan oleh @Mehrdad, jika perlu hanya memiliki string dengan panjang kurang dari 90k karakter (yang masih banyak), sisipan depan akan membangun String dalam waktu yang sama seperti yang dibutuhkan untuk membangun String dengan panjang yang sama dengan menambahkan di bagian akhir. Apa yang saya katakan adalah bahwa penalti waktu memang hebat, tetapi hanya ketika Anda harus membangun string yang sangat besar. Seseorang dapat menggunakan deque dan menggabungkan string di akhir seperti yang ditunjukkan dalam contoh saya.

Sebenarnya kinerja untuk kasus 2 jauh lebih cepat daripada kasus 1, yang sepertinya tidak saya mengerti. Saya berasumsi pertumbuhan buffer internal di StringBuilder akan sama dalam kasus front append dan back append. Saya bahkan menyetel heap minimum ke jumlah yang sangat besar untuk menghindari penundaan dalam pertumbuhan heap, jika itu berperan. Mungkin seseorang yang memiliki pemahaman yang lebih baik bisa berkomentar di bawah ini.


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
Selamat datang di stackoverflow. Harap sertakan penjelasan tentang fungsi kode dan cara menyelesaikan masalah dalam pertanyaan.
bad_coder

1

Anda dapat menggunakan metode sisipkan dengan offset. karena offset disetel ke '0' berarti Anda menambahkan ke depan StringBuilder Anda.

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

CATATAN : karena metode penyisipan menerima semua jenis primitif, Anda dapat menggunakan untuk int, long, char [] dll.


0

Bagaimana tentang:

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

ATAU

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

Tetapi dengan ini, Anda membuat operasi O (N ^ 2) alih-alih O (N).

Cuplikan dari dokumen java:

Menyisipkan representasi string dari argumen Object ke dalam urutan karakter ini. Efek keseluruhannya persis seperti jika argumen kedua diubah menjadi string dengan metode String.valueOf(Object), dan karakter string itu kemudian dimasukkan ke dalam urutan karakter ini pada offset yang ditunjukkan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.