Menggunakan Java 8 untuk mengubah daftar objek menjadi string yang diperoleh dari metode toString ()

206

Ada banyak hal baru yang berguna di Java 8. Misalnya, saya bisa beralih dengan aliran ke daftar objek dan kemudian menjumlahkan nilai dari bidang tertentu dari Objectinstance. Misalnya

public class AClass {
  private int value;
  public int getValue() { return value; }
}

Integer sum = list.stream().mapToInt(AClass::getValue).sum();

Jadi, saya bertanya apakah ada cara untuk membangun Stringyang menggabungkan output toString()metode dari instance dalam satu baris.

List<Integer> list = ...

String concatenated = list.stream().... //concatenate here with toString() method from java.lang.Integer class

Misalkan listmengandung bilangan bulat 1, 2dan 3, saya berharap bahwa concatenatedini "123"atau "1,2,3".

mat_boy
sumber
Kemungkinan rangkap dari Java: convert List <String> ke String
Vadzim

Jawaban:

369

Salah satu cara sederhana adalah menambahkan item daftar Anda di a StringBuilder

   List<Integer> list = new ArrayList<>();
   list.add(1);
   list.add(2);
   list.add(3);

   StringBuilder b = new StringBuilder();
   list.forEach(b::append);

   System.out.println(b);

Anda juga dapat mencoba:

String s = list.stream().map(e -> e.toString()).reduce("", String::concat);

Penjelasan: map mengubah Integer stream ke String stream, lalu dikurangi sebagai gabungan semua elemen.

Catatan: Ini normal reductionyang tampil di O (n 2 )

untuk kinerja yang lebih baik gunakan StringBuilderatau mutable reductionmirip dengan jawaban F. Böller.

String s = list.stream().map(Object::toString).collect(Collectors.joining(","));

Ref: Stream Reduction

Shail016
sumber
2
Ya, bukan solusi inline, tetapi solusi.
mat_boy
tidak mengerti itu. Apa yang kamu harapkan
Shail016
2
saya tidak mengerti mengapa "reduksi normal berjalan di O (n2)". bagi saya itu "terlihat" lebih seperti O (n) ...
datahaki
2
@datahaki Saya bukan orang Jawa, tapi saya kira bahwa rangkaian string iteratif (reduksi) membutuhkan alokasi array (kembali) di setiap iterasi, yang membuatnya O (n ^ 2). joindi sisi lain akan mengalokasikan satu array yang cukup besar untuk menyimpan string terakhir sebelum mengisinya, menjadikannya O (n).
Eli Korvigo
2
Tip yang sangat bagus. Mungkin Anda dapat menyederhanakan menggunakan notasi "::". Jadi, list.stream().map(Object::toString).reduce("", String::concat). Penggunaannya map e-> e.toString()sedikit berlebihan.
e2a
194

Ada seorang kolektor joiningdi API. Ini metode statis di Collectors.

list.stream().map(Object::toString).collect(Collectors.joining(","))

Tidak sempurna karena panggilan yang diperlukan toString, tetapi berhasil. Pembatas yang berbeda dimungkinkan.

F. Böller
sumber
7
Untuk kelengkapan: untuk mendapatkan kode yang tepat untuk bekerja, Anda perluimport static java.util.stream.Collectors.joining;
Mahdi
7
Mengapa kita membutuhkan pemetaan dan `toString 'yang eksplisit? Jika kolektor mengharapkan elemen String maka konversi harus dilakukan secara implisit, bukan ?!
Basel Shishani
10

Kalau-kalau ada orang yang mencoba melakukan ini tanpa java 8, ada trik yang cukup bagus. List.toString () sudah mengembalikan koleksi yang terlihat seperti ini:

[1,2,3]

Bergantung pada persyaratan spesifik Anda, ini dapat diproses pasca-apa pun yang Anda inginkan asalkan item daftar Anda tidak mengandung [] atau,.

Misalnya:

list.toString().replace("[","").replace("]","") 

atau jika data Anda mungkin mengandung tanda kurung:

String s=list.toString();
s = s.substring(1,s.length()-1) 

akan memberi Anda hasil yang cukup masuk akal.

Satu item array pada setiap baris dapat dibuat seperti ini:

list.toString().replace("[","").replace("]","").replaceAll(",","\r\n")

Saya menggunakan teknik ini untuk membuat html tooltips dari daftar di aplikasi kecil, dengan sesuatu seperti:

list.toString().replace("[","<html>").replace("]","</html>").replaceAll(",","<br>")

Jika Anda memiliki array maka mulailah dengan Arrays.asList (daftar) .toString () sebagai gantinya

Saya akan benar-benar memiliki fakta bahwa ini tidak optimal, tetapi tidak seefisien yang Anda kira dan cukup mudah untuk dibaca dan dipahami. Namun, ini cukup tidak fleksibel - khususnya tidak mencoba untuk memisahkan elemen dengan replaceAll jika data Anda mungkin mengandung koma dan menggunakan versi substring jika Anda memiliki tanda kurung siku dalam data Anda, tetapi untuk array angka itu cukup banyak sempurna.

Bill K.
sumber
Meskipun ini biasanya akan berhasil, itu tidak dijamin - Listtidak menegakkan struktur toString(). AbstractCollectionNamun, memang menggunakan struktur ini secara default, dan saya pikir semua Listimplementasi tujuan umum di Jawa SE juga. Sebagai contoh yang tidak, org.springframework.util.AutoPopulatingListdi Spring tidak menerapkan toString()dan dengan demikian akan mengembalikan misalnya " org.springframework.util.AutoPopulatingList@170a1".
M. Justin
Arrays.toString()akan menjadi pilihan yang lebih baik daripada Arrays.asList(list).toString(), karena didefinisikan untuk mengembalikan string yang setara, itu lebih ringkas, dan itu tidak memerlukan penciptaan objek tambahan.
M. Justin
@ M.Justin Bukan titik buruk untuk bagian array dari jawaban ini, tetapi bagaimana dengan "Daftar" sederhana? Anda tidak bisa menggunakan Arrays.toString () untuk itu. Bagaimana Anda menyarankan menggunakan teknik ini pada sesuatu seperti AutoPopulatingList yang Anda sebutkan? Mungkin: ArrayList baru (autoPopulatingList) .toString ()? Atau saya kira Anda bisa mengubahnya menjadi array. Mungkin jika Anda mengalami masalah seperti itu Anda harus berharap Anda berada di 1,8 atau lebih baru dan dapat menggunakan salah satu jawaban lain di utas ini ...
Bill K
5

Jawaban lainnya baik-baik saja. Namun, Anda juga bisa meneruskan Collectors.toList () sebagai parameter ke Stream.collect () untuk mengembalikan elemen sebagai ArrayList.

System.out.println( list.stream().map( e -> e.toString() ).collect( toList() ) );
Eddie B
sumber
Jika Anda menggunakan System.out.print(ln) (list)ia akan menggunakan toString()metode elemen untuk mencetak daftar. Jadi, kode ini hanya mengulangi apa yang terjadi di dalam toStringDaftar.
Shirkam
1
Seharusnya Collectors.toList () kecuali Anda mengimpor statis.
mwieczorek
Yap ... Saya mengimpor statis sebagai contoh. Saya menyatakan, "Collectors.toList ()" di dalam tubuh jawabannya ...;)
Eddie B
2

StringListName = ObjectListName.stream (). Map (m -> m.toString ()) .collect (Collectors.toList ());

Rekha Ghanate
sumber
2

Ada metode dalam API String untuk penggunaan kata sandi "bergabung dengan string", Anda bahkan tidak perlu Stream.

List<String> myStringIterable = Arrays.asList("baguette", "bonjour");

String myReducedString = String.join(",", myStringIterable);

// And here you obtain "baguette,bonjour" in your myReducedString variable
Bachrc
sumber
1
List<String> list = Arrays.asList("One", "Two", "Three");
    list.stream()
            .reduce("", org.apache.commons.lang3.StringUtils::join);

Atau

List<String> list = Arrays.asList("One", "Two", "Three");
        list.stream()
                .reduce("", (s1,s2)->s1+s2);

Pendekatan ini memungkinkan Anda juga membangun hasil string dari daftar objek Contoh

List<Wrapper> list = Arrays.asList(w1, w2, w2);
        list.stream()
                .map(w->w.getStringValue)
                .reduce("", org.apache.commons.lang3.StringUtils::join);

Di sini fungsi pengurangan memungkinkan Anda untuk memiliki beberapa nilai awal yang ingin Anda tambahkan string baru Contoh:

 List<String> errors = Arrays.asList("er1", "er2", "er3");
            list.stream()
                    .reduce("Found next errors:", (s1,s2)->s1+s2);
0vint0
sumber
1

Menguji kedua pendekatan yang disarankan di Shail016 dan jawaban bpedroso ( https://stackoverflow.com/a/24883180/2832140 ), yang sederhana StringBuilder+ append(String)dalam satu forlingkaran, tampaknya mengeksekusi jauh lebih cepat daripada list.stream().map([...].

Contoh: Kode ini berjalan melalui Map<Long, List<Long>>string json build, menggunakan list.stream().map([...]:

if (mapSize > 0) {
    StringBuilder sb = new StringBuilder("[");

    for (Map.Entry<Long, List<Long>> entry : threadsMap.entrySet()) {

        sb.append("{\"" + entry.getKey().toString() + "\":[");
        sb.append(entry.getValue().stream().map(Object::toString).collect(Collectors.joining(",")));
    }
    sb.delete(sb.length()-2, sb.length());
    sb.append("]");
    System.out.println(sb.toString());
}

Di VM dev saya, junit biasanya membutuhkan waktu antara 0,35 dan 1,2 detik untuk menjalankan tes. Sementara, menggunakan kode berikut ini, dibutuhkan antara 0,15 dan 0,33 detik:

if (mapSize > 0) {
    StringBuilder sb = new StringBuilder("[");

    for (Map.Entry<Long, List<Long>> entry : threadsMap.entrySet()) {

        sb.append("{\"" + entry.getKey().toString() + "\":[");

        for (Long tid : entry.getValue()) {
            sb.append(tid.toString() + ", ");
        }
        sb.delete(sb.length()-2, sb.length());
        sb.append("]}, ");
    }
    sb.delete(sb.length()-2, sb.length());
    sb.append("]");
    System.out.println(sb.toString());
}
Lorenzo Cipriani
sumber
0

Bisakah kita coba ini?

public static void main(String []args){
        List<String> stringList = new ArrayList<>();
        for(int i=0;i< 10;i++){
            stringList.add(""+i);
        }
        String stringConcated = String.join(",", stringList);
        System.out.println(stringConcated);

    }
Kumar Abhishek
sumber
0
String actual = list.stream().reduce((t, u) -> t + "," + u).get();
Joe Almore
sumber
7
Biasanya merupakan ide yang baik untuk menambahkan penjelasan ke posting Anda yang berbicara tentang cara kerja kode. Ini memungkinkan pengembang baru untuk memahami apa yang dilakukan kode.
Caleb Kleveter
1
@ CalebKleveter mengurangi a Listmenjadi satu Stringdan memisahkan setiap elemen dengan koma ( ,).
Joe Almore
2
Solusi Anda HANYA berfungsi jika daftar adalah Daftar <String>. OP tidak menentukan kelas seperti itu. Dalam pertanyaannya, sebuah Daftar <Integer> ditunjukkan. Kode Anda tidak dikompilasi dalam kasus itu.
RubioRic
0

Saya akan menggunakan api stream untuk mengubah aliran bilangan bulat menjadi satu string. Masalah dengan beberapa jawaban yang diberikan adalah bahwa mereka menghasilkan runtime O (n ^ 2) karena pembangunan String. Solusi yang lebih baik adalah dengan menggunakan StringBuilder, dan kemudian bergabung dengan string sebagai langkah terakhir.

//              Create a stream of integers 
    String result = Arrays.stream(new int[]{1,2,3,4,5,6 })                
            // collect into a single StringBuilder
            .collect(StringBuilder::new, // supplier function
                    // accumulator - converts cur integer into a string and appends it to the string builder
                    (builder, cur) -> builder.append(Integer.toString(cur)),
                    // combiner - combines two string builders if running in parallel
                    StringBuilder::append) 
            // convert StringBuilder into a single string
            .toString();

Anda dapat mengambil proses ini selangkah lebih maju dengan mengubah koleksi objek menjadi string tunggal.

// Start with a class definition
public static class AClass {
    private int value;
    public int getValue() { return value; }
    public AClass(int value) { this.value = value; }

    @Override
    public String toString() {
        return Integer.toString(value);
    }
}

// Create a stream of AClass objects
        String resultTwo = Arrays.stream(new AClass[]{
                new AClass(1),
                new AClass(2),
                new AClass(3),
                new AClass(4)
        })
                // transform stream of objects into a single string
                .collect(StringBuilder::new,
                        (builder, curObj) -> builder.append(curObj.toString()),
                        StringBuilder::append
                )
            // finally transform string builder into a single string
            .toString();
Digital-Logika
sumber
-1

Dengan Java 8+

String s = Arrays.toString(list.stream().toArray(AClass[]::new));

Bukan yang paling efisien, tetapi ini adalah solusi dengan sejumlah kecil kode.

James Wierzba
sumber
-2

Anda juga bisa melakukan ini.

    List<String> list = Arrays.asList("One", "Two", "Three");
    String result = String.join(", ", list);
    System.out.println(result);
Evgenii
sumber
Solusi Anda HANYA berfungsi jika daftar adalah Daftar <String>. OP tidak menentukan kelas seperti itu. Dalam pertanyaannya, sebuah Daftar <Integer> ditunjukkan.
RubioRic