Bir nesne listesini toString () yönteminden elde edilen bir dizeye dönüştürmek için Java 8'i kullanma


206

Java 8'de birçok yararlı yeni şey var. Örneğin, bir nesne listesi üzerinden bir akışla yineleyebilir ve daha sonra Object'örneklerinin belirli bir alanındaki değerleri toplayabilirim . Örneğin

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

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

Bu nedenle, tek bir satırdaki örneklerden yöntemin Stringçıktısını birleştiren bir oluşturmanın herhangi bir yolu olup olmadığını soruyorum toString().

List<Integer> list = ...

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

Varsayalım ki listtamsayıları içeren 1, 2ve 3ben bekliyoruz concatenatedolduğu "123"veya "1,2,3".


Olası Java
String'e

Yanıtlar:


369

Basit bir yol, liste öğelerinizi bir 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);

ayrıca deneyebilirsiniz:

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

Açıklama: map, Tamsayı akışını Dize akışına dönüştürür, daha sonra tüm öğelerin birleşimi olarak azaltılır.

Not: Bu normal reductionO (n 2 ) 'de çalışır

daha iyi performans için F. Böller'in cevabına benzer bir StringBuilderveya mutable reductionbenzeri kullanın.

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

Ref: Akış Azaltma


2
Evet, satır içi bir çözüm değil, bir çözüm.
mat_boy

anlamadı. Ne bekliyorsun?
Shail016

2
neden "O (n2) performans normal azalma" anlamıyorum. bana daha çok O (n) gibi görünüyor ...
datahaki

2
@datahaki Ben Java adam değilim, ama yinelemeli dize birleştirme (azaltma) O (n ^ 2) yapar her yineleme dizi (yeniden) tahsis gerektirir tahmin ediyorum. joindiğer tarafta, son dizgiyi doldurmadan önce depolayacak kadar büyük tek bir diziyi önceden konumlandırarak O (n) haline getirir.
Eli Korvigo

2
Çok iyi bir ipucu. Belki "::" gösterimini kullanarak basitleştirebilirsiniz. Yani list.stream().map(Object::toString).reduce("", String::concat),. Kullanmak map e-> e.toString()biraz gereksizdir.
e2a

194

joiningAPI'da bir koleksiyoncu var . Bu statik bir yöntemdir Collectors.

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

Gerekli çağrı nedeniyle mükemmel değil toString, ama çalışıyor. Farklı sınırlayıcılar mümkündür.


7
Tamlık için: tam olarak bu kodun çalışmasını sağlamak içinimport static java.util.stream.Collectors.joining;
Mehdi

7
Neden eşleştirmeye ve açık `` toString '' e ihtiyacımız var? Toplayıcı String öğelerini bekliyorsa, dönüşüm dolaylı olarak çağrılmalıdır, hayır ?!
Basel Shishani

10

Herkesin java 8 olmadan bunu yapmaya çalışması durumunda, oldukça iyi bir hile var. List.toString () zaten şuna benzer bir koleksiyon döndürür:

[1,2,3]

Özel gereksinimlerinize bağlı olarak, liste öğeleriniz [] veya, içermediği sürece bu istediğiniz her şey için sonradan işlenebilir.

Örneğin:

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

veya verileriniz köşeli parantez içeriyorsa:

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

size oldukça makul bir çıktı alacak.

Her satırda bir dizi öğesi şu şekilde oluşturulabilir:

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

Bu tekniği, küçük bir uygulamadaki bir listeden html araç ipuçları yapmak için kullandım:

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

Bir diziniz varsa Arrays.asList (list) .toString () ile başlayın

Bunun optimal olmadığı gerçeğine tamamen sahip olacağım, ancak düşündüğünüz kadar verimsiz değil ve okumak ve anlamak oldukça basit. Bununla birlikte, oldukça esnek değildir - özellikle öğeleri replace ile ayırmaya çalışmayın.Verileriniz virgül içeriyorsa ve verilerinizde köşeli parantez varsa alt dize sürümünü kullanır, ancak bir dizi sayı için mükemmel.


Bu genellikle işe yarayacak olsa da List, yapısını zorlamamak garanti edilmez toString(). AbstractCollectionancak, bu yapıyı varsayılan olarak kullanır ve ListJava SE'deki tüm genel amaçlı uygulamaların da yaptığını düşünüyorum . Yapılmayan bir örnek olarak, org.springframework.util.AutoPopulatingListBahar'da uygulama yapılmaz toString()ve bu nedenle " org.springframework.util.AutoPopulatingList@170a1" gibi geri dönecektir .
M. Justin

Arrays.toString()daha iyi bir seçim olacaktır Arrays.asList(list).toString()eşdeğer bir dize döndürmek için tanımlandığı gibi, daha özlü, ve o ek nesne oluşturulmasını gerektirmez.
M. Justin

@ M.Justin Bu cevabın dizi kısmı için kötü bir nokta değil, ama düz bir "Liste" ne olacak? Üzerinde gerçekten Arrays.toString () kullanamazsınız. Bahsettiğiniz AutoPopulatingList gibi bir şeyde bu tekniği nasıl kullanmanızı önerirsiniz? Belki: yeni ArrayList (autoPopulatingList) .toString ()? Ya da sanırım onu ​​bir diziye dönüştürebilirsiniz. Belki de böyle bir problemle karşılaşırsanız, 1.8 veya daha yeni bir sürümde olduğunuzu ve bu konudaki diğer cevaplardan birini kullanabileceğinizi ummalısınız ...
Bill K

5

Diğer cevaplar iyi. Ancak, öğeleri ArrayList olarak döndürmek için Collectors.toList () öğesini Stream.collect () öğesine parametre olarak da iletebilirsiniz .

System.out.println( list.stream().map( e -> e.toString() ).collect( toList() ) );

Eğer kullanırsanız System.out.print(ln) (list)kullanacağını toString()listesini yazdırmak için elementlerin yöntemini. Yani, bu kod parçası Listenin içinde olanları tekrarlıyor toString.
Shirkam

1
Statik içe aktarmadığınız sürece Collectors.toList () olmalıdır.
mwieczorek

Evet ... Örnek için statik ithal ettim. Dedim ki, cevabın gövdesinde "Collectors.toList ()" ...;)
Eddie B

2

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


2

Dize API'sinde "dize listesine katılma" kullanıcı işlemleri için bir yöntem vardır, Akışa bile ihtiyacınız yoktur.

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

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

// And here you obtain "baguette,bonjour" in your myReducedString variable

1
List<String> list = Arrays.asList("One", "Two", "Three");
    list.stream()
            .reduce("", org.apache.commons.lang3.StringUtils::join);

Veya

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

Bu yaklaşım, bir nesne listesinden bir dize sonucu oluşturmanıza olanak sağlar Örnek

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

Burada reduce işlevi, yeni dize eklemek istediğiniz bazı başlangıç ​​değerlerine sahip olmanızı sağlar Örnek:

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

1

Bir döngü içindeki basit + , Shail016 ve bpedroso yanıtında ( https://stackoverflow.com/a/24883180/2832140 ) önerilen her iki yaklaşımı da test etmek,StringBuilderappend(String)forlist.stream().map([...] .

Örnek: Bu kod Map<Long, List<Long>>, aşağıdakileri kullanarak bir json dizesi oluşturur 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());
}

Geliştirme VM'imde junit, testi gerçekleştirmek için genellikle 0,35 ile 1,2 saniye arasında sürer. Bu kodu kullanırken, 0,15 ile 0,33 saniye arasında sürer:

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());
}

0

Bunu deneyebilir miyiz.

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);

    }

0
String actual = list.stream().reduce((t, u) -> t + "," + u).get();

7
Genellikle, postanıza kodun nasıl çalıştığından bahsedecek bir açıklama eklemek iyi bir fikirdir. Bu, yeni geliştiricilerin kodun ne yaptığını anlamalarını sağlar.
Caleb Kleveter

1
Bir azaltır @CalebKleveter Listtek için Stringve virgül, her öğe, ayrı ( ,).
Joe Almore

2
Çözümünüz SADECE liste <String> ise çalışır. OP böyle bir sınıf belirtmedi. Onun sorusunda <Integer> Listesi bile işaret ediliyor. Bu durumda kodunuz derlenmez.
RubioRic

0

Bir tamsayı akışını tek bir dizeye dönüştürmek için api akışlarını kullanacağım. Sağlanan cevapların bazılarında sorun, Dize oluşturma nedeniyle bir O (n ^ 2) çalışma zamanı üretmesidir. Daha iyi bir çözüm bir StringBuilder kullanmak ve sonra son adım olarak dizeleri birleştirmektir.

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

Nesne koleksiyonunu tek bir dizeye dönüştürerek bu işlemi bir adım daha ileri taşıyabilirsiniz.

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

-1

Java 8+ ile

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

En verimli değil, ancak az miktarda kod içeren bir çözümdür.


-2

Ayrıca, bunu yapabilirsiniz.

    List<String> list = Arrays.asList("One", "Two", "Three");
    String result = String.join(", ", list);
    System.out.println(result);

Çözümünüz SADECE liste <String> ise çalışır. OP böyle bir sınıf belirtmedi. Onun sorusunda <Integer> Listesi bile işaret ediliyor.
RubioRic
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.