Beste manier om een ArrayList naar een string te converteren

Ik heb een ArrayListdie ik volledig als een string wil uitvoeren. In wezen wil ik het in volgorde uitvoeren met behulp van de toStringvan elk element, gescheiden door tabs. Is er een snelle manier om dit te doen? Je zou er doorheen kunnen lopen (of elk element verwijderen) en het samenvoegen tot een string, maar ik denk dat dit erg traag zal zijn.


Antwoord 1, autoriteit 100%

Java 8 introduceert een String.join(separator, list)methode; zie Vitalii Federenko’s antwoord.

Vóór Java 8 was het gebruik van een lus om de ArrayListte herhalen de enige optie:

Gebruik deze code NIET, lees verder tot onderaan dit antwoord om te zien waarom het niet wenselijk is en welke code in plaats daarvan moet worden gebruikt:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
String listString = "";
for (String s : list)
{
    listString += s + "\t";
}
System.out.println(listString);

In feite zal een string-aaneenschakeling prima zijn, aangezien de javac-compiler de string-concatenatie zal optimaliseren als een reeks append-bewerkingen op een StringBuildertoch. Hier is een deel van de demontage van de bytecode uit de for-lus van het bovenstaande programma:

  61:  new #13; //class java/lang/StringBuilder
   64:  dup
   65:  invokespecial   #14; //Method java/lang/StringBuilder."<init>":()V
   68:  aload_2
   69:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  aload   4
   74:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   77:  ldc #16; //String \t
   79:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   82:  invokevirtual   #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

Zoals te zien is, optimaliseert de compiler die lus door een StringBuilderte gebruiken, dus prestaties zouden geen grote zorg moeten zijn.

(OK, op het tweede gezicht wordt de StringBuildergeïnstantieerd bij elke iteratie van de lus, dus het is misschien niet de meest efficiënte bytecode. Instantie en gebruik van een expliciete StringBuilderzou waarschijnlijk betere prestaties opleveren.)

In feite denk ik dat het hebben van elke vorm van uitvoer (of het nu naar schijf of naar het scherm is) op zijn minst een orde van grootte langzamer zal zijn dan dat je je zorgen hoeft te maken over de prestaties van string-aaneenschakelingen.

Bewerken:Zoals aangegeven in de opmerkingen, creëert de bovenstaande compileroptimalisatie inderdaad een nieuwe instantie van StringBuilderbij elke iteratie. (Wat ik al eerder heb opgemerkt.)

De meest geoptimaliseerde techniek om te gebruiken is de reactie van Paul Tomblin, omdat het slechts een enkel StringBuilder-object instantieert buiten de for-lus.

Herschrijven naar de bovenstaande code om:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder();
for (String s : list)
{
    sb.append(s);
    sb.append("\t");
}
System.out.println(sb.toString());

De StringBuilderzal slechts eenmaal buiten de lus worden geïnstantieerd en alleen de twee aanroepen van de methode appendbinnen de lus worden gedaan, zoals blijkt uit deze bytecode (die laat zien de instantie van StringBuilderen de lus):

  // Instantiation of the StringBuilder outside loop:
   33:  new #8; //class java/lang/StringBuilder
   36:  dup
   37:  invokespecial   #9; //Method java/lang/StringBuilder."<init>":()V
   40:  astore_2
   // [snip a few lines for initializing the loop]
   // Loading the StringBuilder inside the loop, then append:
   66:  aload_2
   67:  aload   4
   69:  invokevirtual   #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  pop
   73:  aload_2
   74:  ldc #15; //String \t
   76:  invokevirtual   #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   79:  pop

De handoptimalisatie zou dus inderdaad beter moeten presteren, aangezien de binnenkant van de for-lus korter is en het niet nodig is om bij elke iteratie een StringBuilderte maken.


Antwoord 2, autoriteit 97%

In Java 8 of hoger:

String listString = String.join(", ", list);

In het geval dat de listniet van het type String is, kan een toetredende collector worden gebruikt:

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

Antwoord 3, autoriteit 94%

Als je dit toevallig op Android doet, is er een mooi hulpprogramma hiervoor genaamd TextUtilsmet een methode .join(String delimiter, Iterable).

List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);

Natuurlijk niet veel gebruikt buiten Android, maar ik dacht ik voeg het toe aan deze thread…


Antwoord 4, autoriteit 67%

Download de Apache Commons Lang en gebruik de methode

StringUtils.join(list)
 StringUtils.join(list, ", ") // 2nd param is the separator.

Je kunt het natuurlijk zelf implementeren, maar hun code is volledig getest en is waarschijnlijk de best mogelijke implementatie.

Ik ben een grote fan van de Apache Commons-bibliotheek en ik vind het ook een geweldige aanvulling op de Java Standard-bibliotheek.


Antwoord 5, autoriteit 39%

Dit is een vrij oude vraag, maar ik denk dat ik net zo goed een moderner antwoord kan toevoegen – gebruik de Joiner-klasse van Guave:

String joined = Joiner.on("\t").join(list);

Antwoord 6, autoriteit 25%

Het veranderen van Lijstin een leesbare en betekenisvolle Stringis een veel voorkomende vraag die iedereen kan tegenkomen.

Geval 1. Als je StringUtils van apache in je klassenpad hebt (vanaf rogerdpack en Ravi Wallau):

import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);

Geval 2. Als u alleen manieren uit JDK(7) wilt gebruiken:

import java.util.Arrays;
String str = Arrays.toString(myList.toArray()); 

Bouw nooit zelf wielen, gebruik geen lus voor deze taak van één regel.


Antwoord 7, autoriteit 18%

Als u op zoek was naar een snelle one-liner, kunt u vanaf Java 5 dit doen:

myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")

Bovendien, als het uw doel is om alleen de inhoud af te drukken en u zich minder zorgen maakt over de “\t”, kunt u dit eenvoudig doen:

myList.toString()

die een tekenreeks retourneert zoals

[str1, str2, str3]

Als u een Array (niet ArrayList) heeft, kunt u hetzelfde als volgt bereiken:

Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")

Antwoord 8, autoriteit 11%

Loop er doorheen en bel tostring. Er is geen magische manier, en als er, wat denk je dat het zou doen onder de covers anders dan het doorlopen? Over de enige micro-optimalisatie zou zijn om stringbuilder te gebruiken in plaats van een string, en zelfs dat is geen enorme win-aaneengeschakelde snaren verandert in stringbuilder onder de dekens, maar tenminste als je het op die manier schrijft, kun je zien wat er aan de hand is.

StringBuilder out = new StringBuilder();
for (Object o : list)
{
  out.append(o.toString());
  out.append("\t");
}
return out.toString();

Antwoord 9, Autoriteit 10%

De meeste Java-projecten hebben vaak Apache-Commons Lang beschikbaar. StringUtils.join () Methoden zijn erg mooi en heeft verschillende smaken om bijna elke behoeften te ontmoeten.

public static java.lang.String join(java.util.Collection collection,
                                    char separator)
public static String join(Iterator iterator, String separator) {
    // handle null, zero and one elements before building a buffer 
    Object first = iterator.next();
    if (!iterator.hasNext()) {
        return ObjectUtils.toString(first);
    }
    // two or more elements 
    StringBuffer buf = 
        new StringBuffer(256); // Java default is 16, probably too small 
    if (first != null) {
        buf.append(first);
    }
    while (iterator.hasNext()) {
        if (separator != null) {
            buf.append(separator);
        }
        Object obj = iterator.next();
        if (obj != null) {
            buf.append(obj);
        }
    }
    return buf.toString();
}

Parameters:

Collection – De verzameling waarden om samen te voegen, kan null

zijn

scheidingsteken– het te gebruiken scheidingsteken

Retourneert: de samengevoegde string, null if
null iterator invoer

Sinds:
2.3


Antwoord 10, autoriteit 5%

Android heeft een TextUtil-klasse die u kunt gebruiken http://developer.android.com/reference/android /text/TextUtils.html

String implode = TextUtils.join("\t", list);

Antwoord 11, autoriteit 5%

Voor dit eenvoudige gebruik kun je de tekenreeksen eenvoudig samenvoegen met een komma. Als u Java 8 gebruikt:

String csv = String.join("\t", yourArray);

anders heeft commons-lang een join()-methode:

String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");

Antwoord 12, autoriteit 4%

Een elegante manier om met volgtekens om te gaan is door Klassescheidingsteken

StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();

De methode toString van Class Separator retourneert de separator, behalvevoor de eerste aanroep. We drukken de lijst dus af zonder achterlopende (of in dit geval) voorloopscheidingstekens.


Antwoord 13, autoriteit 4%

In Java 8 is het eenvoudig. Zie voorbeeld voor lijst met gehele getallen:

String result = Arrays.asList(1,2,3).stream().map(Object::toString).reduce((t, u) -> t + "\t" + u).orElse("");

of multiline-versie (die eenvoudiger is om te lezen):

String result = Arrays.asList(1,2,3).stream()
    .map(Object::toString)
    .reduce((t, u) -> t + "\t" + u)
    .orElse("");

Update – een kortere versie

String result = Arrays.asList(1,2,3).stream()
                .map(Object::toString)
                .collect(Collectors.joining("\t"));

Antwoord 14, Autoriteit 2%

Het is een O(n)algoritme in beide richtingen (tenzij u een aantal multi-threaded oplossing hebt gedaan waar u de lijst in meerdere sublijsten hebt gebroken, maar ik denk niet dat dit is waar u om vraagt ).

Gebruik gewoon een StringBuilderzoals hieronder:

StringBuilder sb = new StringBuilder();
for (Object obj : list) {
  sb.append(obj.toString());
  sb.append("\t");
}
String finalString = sb.toString();

De StringBuilderis een stuk sneller dan string-aaneenvoeging omdat u geen onmiddellijk een StringObject op elke aaneenvoeging opnieuw kunt opnemen.


Antwoord 15

Als u toevallig op Android bent en u nog geen aansluiting gebruikt (bijvoorbeeld omdat het nog steeds ondersteuning biedt voor onmiddellijke run), en als u meer controle wilt over het formatteren van de resulterende tekenreeks (bijvoorbeeld u wilt gebruiken Newline-teken als de scheidingslijn van elementen), en toevallig de Streamsupport-bibliotheek (voor het gebruik van streams op Java 7 of eerdere versies van de compiler), kunt u zoiets gebruiken (ik heb deze methode in mijn Listutils-klasse gebruikt ):

public static <T> String asString(List<T> list) {
    return StreamSupport.stream(list)
            .map(Object::toString)
            .collect(Collectors.joining("\n"));
}

En natuurlijk, zorg ervoor dat u TOSTRING () op uw lijst voor objectobjecten implementeert.


Antwoord 16

Als u niet wilt dat het laatste \ t na het laatste element, moet u de index gebruiken om te controleren, maar vergeet niet dat dit alleen “werken” (dwz o (n)) is wanneer de lijsten de willekeurige toerswerk implementeren.

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder(list.size() * apprAvg); // every apprAvg > 1 is better than none
for (int i = 0; i < list.size(); i++) {
    sb.append(list.get(i));
    if (i < list.size() - 1) {
        sb.append("\t");
    }
}
System.out.println(sb.toString());

Antwoord 17

in één regel:
Van [12,0,178,12] tot 12 0 1 78 12

String srt= list.toString().replaceAll("\\[|\\]|,","");

Antwoord 18

De onderstaande code kan u helpen,

List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
String str = list.toString();
System.out.println("Step-1 : " + str);
str = str.replaceAll("[\\[\\]]", "");
System.out.println("Step-2 : " + str);

Uitvoer:

Step-1 : [1, 2, 3]
Step-2 : 1, 2, 3

Antwoord 19

Misschien niet de beste manier, maar elegante manier.

Arrays.deepToString(Arrays.asList(“Test”, “Test2”)

import java.util.Arrays;
    public class Test {
        public static void main(String[] args) {
            System.out.println(Arrays.deepToString(Arrays.asList("Test", "Test2").toArray()));
        }
    }

Uitvoer

[Test, Test2]


Antwoord 20

Zou het volgende goed zijn:

List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));   

Antwoord 21

Als je Eclipse Collectionsgebruikt, kun je de makeString()methode.

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Assert.assertEquals(
    "one\ttwo\tthree",
    ArrayListAdapter.adapt(list).makeString("\t"));

Als u uw ArrayListkunt converteren naar een FastList, kunt u de adapter verwijderen.

Assert.assertEquals(
    "one\ttwo\tthree",
    FastList.newListWith("one", "two", "three").makeString("\t"));

Opmerking: ik ben een toegewijde voor Eclipse Collections.


Antwoord 22

List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()

Je geeft aan de new StringJoinerde tekenreeks door die je als scheidingsteken wilt gebruiken. Als je een CSV wilt maken: new StringJoiner(", ");


Antwoord 23

Voor het scheiden met tabbladen in plaats van printlnkunt u print

gebruiken

ArrayList<String> mylist = new ArrayList<String>();
mylist.add("C Programming");
mylist.add("Java");
mylist.add("C++");
mylist.add("Perl");
mylist.add("Python");
for (String each : mylist)
{       
    System.out.print(each);
    System.out.print("\t");
}

Antwoord 24

Ik zie nogal wat voorbeelden die afhankelijk zijn van aanvullende bronnen, maar het lijkt erop dat dit de eenvoudigste oplossing zou zijn: (wat ik in mijn eigen project heb gebruikt) die in feite gewoon het converteren van een ArrayList naar een Array is en dan naar een lijst.

   List<Account> accounts = new ArrayList<>();
   public String accountList() 
   {
      Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
      String listingString = Arrays.toString(listingArray);
      return listingString;
   }

Antwoord 25

Dit is nu nogal een oud gesprek en Apache Commons gebruiken nu intern een stringbuilder: http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/stringutils.html#line.3045

Dit zal zoals we kennen de prestaties verbeteren, maar als de uitvoering van cruciaal belang is, kan de gebruikte methode enigszins inefficiënt zijn. Overwegende dat de interface flexibel is en een consistent gedrag in verschillende verzamelingstypen mogelijk maakt, is het enigszins inefficiënt voor lijsten, wat het type verzameling is in de oorspronkelijke vraag.

Ik baseer dit in dat we een beetje overhead gaan, die we zouden vermijden door simpelweg iteratie door de elementen in een traditioneel voor lus. In plaats daarvan gebeurt er nog meer dingen achter de schermen controleren op gelijktijdige aanpassingen, methode-oproepen enz. De verbeterde voor de lus zal aan de andere kant het gevolg zijn van dezelfde overhead, aangezien de iterator wordt gebruikt op het oerabebeleringsobject (de lijst).


Antwoord 26

U kunt hiervoor een regex gebruiken. Dit is net zo beknopt als het krijgt

System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));

Antwoord 27

Hoe zit het met deze functie:

public static String toString(final Collection<?> collection) {
    final StringBuilder sb = new StringBuilder("{");
    boolean isFirst = true;
    for (final Object object : collection) {
        if (!isFirst)
            sb.append(',');
        else
            isFirst = false;
        sb.append(object);
    }
    sb.append('}');
    return sb.toString();
}

het werkt voor elk type verzameling…

Other episodes