it-swarm.com.de

Die raffinierteste Methode zum Erstellen von durch Kommas getrennten Zeichenfolgen aus einer Sammlung / einem Array / einer Liste?

Während meiner Arbeit mit Datenbanken habe ich festgestellt, dass ich Abfragezeichenfolgen schreibe und dass ich in diesen Zeichenfolgen verschiedene Einschränkungen für die where-Klausel aus einer Liste/einem Array/einer Sammlung festlegen muss. Sollte so aussehen:

select * from customer 
where customer.id in (34, 26, ..., 2);

Sie können dies vereinfachen, indem Sie dies auf die Frage reduzieren, ob Sie eine Sammlung von Zeichenfolgen haben und eine durch Kommas getrennte Liste dieser Zeichenfolgen in nur einer Zeichenfolge erstellen möchten.

Mein Ansatz, den ich bisher verwendet habe, ist ungefähr so:

String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
    if(first) {
        result+=string;
        first=false;
    } else {
        result+=","+string;
    }
}

Aber das ist, wie man sieht, sehr hässlich. Sie können auf den ersten Blick nicht sehen, was dort passiert, insbesondere wenn die erstellten Zeichenfolgen (wie jede SQL-Abfrage) kompliziert werden.

Was ist Ihre (elegantere) Art?

97
maerch

Da Zeichenfolgen unveränderlich sind, können Sie die StringBuilder-Klasse verwenden, wenn Sie die Zeichenfolge im Code ändern möchten.

Die StringBuilder-Klasse kann als veränderbares String-Objekt angesehen werden, das mehr Speicher reserviert, wenn der Inhalt geändert wird.

Der ursprüngliche Vorschlag in der Frage kann noch klarer und effizienter formuliert werden, indem das redundante nachgestellte Komma berücksichtigt wird:

    StringBuilder result = new StringBuilder();
    for(String string : collectionOfStrings) {
        result.append(string);
        result.append(",");
    }
    return result.length() > 0 ? result.substring(0, result.length() - 1): "";
85
gimel

Verwenden Sie die Google Guava APIjoin -Methode:

Joiner.on(",").join(collectionOfStrings);
88
Julie

Ich habe mir gerade Code angesehen, der dies heute getan hat. Dies ist eine Variation der Antwort von AviewAnew.

collectionOfStrings = /* source string collection */;
String csList = StringUtils.join(collectionOfStrings.toArray(), ",");

Das von uns verwendete StringUtils (<- commons.lang 2.x oder commons.lang 3.x ) stammt von Apache Commons .

74
Ogre Psalm33

Die Art und Weise, wie ich diese Schleife schreibe, ist:

StringBuilder buff = new StringBuilder();
String sep = "";
for (String str : strs) {
    buff.append(sep);
    buff.append(str);
    sep = ",";
}
return buff.toString();

Mach dir keine Sorgen über die Leistung von Sep. Eine Zuordnung ist sehr schnell. Hotspot schält ohnehin die erste Iteration einer Schleife ab (da es häufig mit Unregelmäßigkeiten wie Null und mono/bimorphen Inlining-Prüfungen zu tun hat).

Wenn Sie es häufig verwenden (mehr als einmal), fügen Sie es einer gemeinsamen Methode hinzu.

Es gibt eine weitere Frage zum Stackoverflow, die sich mit dem Einfügen einer Liste von IDs in eine SQL-Anweisung befasst.

47

Seit Java 8 können Sie Folgendes verwenden:

40
Abdull

Ich fand das Iterator-Idiom elegant, weil es einen Test für mehr Elemente enthält (weggelassener Null-/Leertest für die Kürze):

public static String convert(List<String> list) {
    String res = "";
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        res += iterator.next() + (iterator.hasNext() ? "," : "");
    }
    return res;
}
11
Miguel Ping

Es gibt viele manuelle Lösungen dafür, aber ich wollte Julies Antwort oben wiederholen und aktualisieren. Verwenden Sie Google Collections Joiner-Klasse .

Joiner.on(", ").join(34, 26, ..., 2)

Es behandelt Variablen, Iterables und Arrays und Trennzeichen von mehr als einem Zeichen (im Gegensatz zu Gimmels Antwort). Es behandelt auch Nullwerte in Ihrer Liste, wenn Sie es brauchen.

8
case nelson

Hier ist eine unglaublich generische Version, die ich aus einer Kombination der vorherigen Vorschläge erstellt habe:

public static <T> String buildCommaSeparatedString(Collection<T> values) {
    if (values==null || values.isEmpty()) return "";
    StringBuilder result = new StringBuilder();
    for (T val : values) {
        result.append(val);
        result.append(",");
    }
    return result.substring(0, result.length() - 1);
}
7
Jeff
String.join(", ", collectionOfStrings)

verfügbar in der Java8-API.

alternative zu (ohne dass eine Google Guava-Abhängigkeit hinzugefügt werden muss):

Joiner.on(",").join(collectionOfStrings);
7
robjwilkins

Du könntest es versuchen

List collections = Arrays.asList(34, 26, "...", 2);
String asString = collection.toString();
// justValues = "34, 26, ..., 2"
String justValues = asString.substring(1, asString.length()-1);
5
Peter Lawrey

Dies ist die bisher kürzeste Lösung, mit Ausnahme der Verwendung von Guava oder Apache Commons

String res = "";
for (String i : values) {
    res += res.isEmpty() ? i : ","+i;
}

Gut mit 0,1 und n Elementliste. Sie müssen jedoch nach einer Nullliste suchen. Ich benutze dies in GWT, so dass ich dort ohne StringBuilder gut bin. Und für kurze Listen mit nur ein paar Elementen ist es auch woanders ok;)

4
iTake

In Android solltest du folgendes verwenden:

TextUtils.join(",",collectionOfStrings.toArray());
4
Pascalius

Für den Fall, dass jemand in jüngerer Zeit darüber gestolpert ist, habe ich eine einfache Variante mit Java 8 reduce() hinzugefügt. Sie enthält auch einige der bereits erwähnten Lösungen von anderen:

import Java.util.Arrays;
import Java.util.List;

import org.Apache.commons.lang.StringUtils;    

import com.google.common.base.Joiner;

public class Dummy {
  public static void main(String[] args) {

    List<String> strings = Arrays.asList("abc", "de", "fg");
    String commaSeparated = strings
        .stream()
        .reduce((s1, s2) -> {return s1 + "," + s2; })
        .get();

    System.out.println(commaSeparated);

    System.out.println(Joiner.on(',').join(strings));

    System.out.println(StringUtils.join(strings, ","));

  }
}
4
Christof

Ich denke, es ist keine gute Idee, den SQL-Code zu konstruieren, der die where-Klausel-Werte verkettet, wie Sie es tun:

SELECT.... FROM.... WHERE ID IN( value1, value2,....valueN)

Wobei valueX aus einer Liste von Zeichenfolgen stammt.

Erstens, wenn Sie Strings vergleichen, müssen diese in Anführungszeichen gesetzt werden, und dies ist nicht trivial, wenn die Strings ein Anführungszeichen enthalten könnten.

Zweitens ist ein SQL-Injection-Angriff möglich, wenn die Werte vom Benutzer oder einem anderen System stammen.

Es ist viel ausführlicher, aber was Sie tun sollten, ist eine Zeichenfolge wie diese zu erstellen:

SELECT.... FROM.... WHERE ID IN( ?, ?,....?)

und binden Sie dann die Variablen mit Statement.setString(nParameter,parameterValue).

4
Telcontar

Nur eine andere Methode, um mit diesem Problem umzugehen. Nicht die kürzeste, aber sie ist effizient und erledigt die Arbeit.

/**
 * Creates a comma-separated list of values from given collection.
 * 
 * @param <T> Value type.
 * @param values Value collection.
 * @return Comma-separated String of values.
 */
public <T> String toParameterList(Collection<T> values) {
   if (values == null || values.isEmpty()) {
      return ""; // Depending on how you want to deal with this case...
   }
   StringBuilder result = new StringBuilder();
   Iterator<T> i = values.iterator();
   result.append(i.next().toString());
   while (i.hasNext()) {
      result.append(",").append(i.next().toString());
   }
   return result.toString();
}
3
silverminken

Wenn Sie Spring verwenden, können Sie Folgendes tun:

StringUtils.arrayToCommaDelimitedString(
    collectionOfStrings.toArray()
)

(Paket org.springframework.util)

2
weekens

Es gibt Java Bibliotheken von Drittanbietern, die die String-Join-Methode bereitstellen, aber Sie möchten wahrscheinlich keine Bibliothek nur für so etwas Einfaches verwenden. Ich würde einfach eine Hilfsmethode wie erstellen Dies ist meiner Meinung nach ein bisschen besser als Ihre Version. Es verwendet StringBuffer, was effizienter ist, wenn Sie viele Zeichenfolgen verbinden müssen, und es funktioniert auf einer Sammlung eines beliebigen Typs.

public static <T> String join(Collection<T> values)
{
    StringBuffer ret = new StringBuffer();
    for (T value : values)
    {
        if (ret.length() > 0) ret.append(",");
        ret.append(value);
    }
    return ret.toString();
}

Ein weiterer Vorschlag für die Verwendung von Collection.toString () ist kürzer, setzt jedoch voraus, dass Collection.toString () eine Zeichenfolge in einem ganz bestimmten Format zurückgibt, auf das ich mich persönlich nicht verlassen möchte.

2
Denis Fradlin

wenn Sie ein Array haben, können Sie Folgendes tun:

Arrays.asList(parameters).toString()
1
cloudy_weather

Ich bin nicht sicher, wie "anspruchsvoll" das ist, aber es ist sicherlich ein bisschen kürzer. Es funktioniert mit verschiedenen Sammlungsarten, z. Setze <Integer>, List <String>, etc.

public static final String toSqlList(Collection<?> values) {

    String collectionString = values.toString();

    // Convert the square brackets produced by Collection.toString() to round brackets used by SQL
    return "(" + collectionString.substring(1, collectionString.length() - 1) + ")";
}

Übung für den Leser: ändere diese Methode so, dass sie eine leere/leere Sammlung korrekt verarbeitet :)

1
Dónal

Eine weitere Option, basierend auf dem, was ich hier sehe (mit geringfügigen Änderungen).

public static String toString(int[] numbers) {
    StringBuilder res = new StringBuilder();
    for (int number : numbers) {
        if (res.length() != 0) {
            res.append(',');
        }
        res.append(number);
    }
    return res.toString();
}
1
elcuco

Ich habe gerade einen Test für meine Bibliothek eingecheckt Dollar :

@Test
public void join() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    String string = $(list).join(",");
}

es erstellt einen fließenden Wrapper um Listen/Arrays/Strings/etc mit nur einem statischen Import : $.

[~ # ~] nb [~ # ~] :

unter Verwendung von Bereichen kann die vorherige Liste als $(1, 5).join(",") umgeschrieben werden

1
dfa

Was den Code hässlich macht, ist die spezielle Behandlung für den ersten Fall. Die meisten Zeilen in diesem kleinen Snippet widmen sich nicht der Routinearbeit des Codes, sondern der Behandlung dieses Sonderfalls. Und genau das lösen Alternativen wie Gimels, indem sie das spezielle Handling über den Tellerrand schieben. Es gibt einen Sonderfall (Sie könnten also sowohl Anfang als auch Ende als Sonderfälle betrachten - aber nur einer von ihnen muss speziell behandelt werden), sodass die Behandlung innerhalb der Schleife unnötig kompliziert ist.

1
Carl Manaster

Join-Methoden sind in Arrays und den Klassen verfügbar, die AbstractCollections erweitern, jedoch die toString() -Methode nicht überschreiben (wie praktisch alle Sammlungen in Java.util).

Zum Beispiel:

String s= Java.util.Arrays.toString(collectionOfStrings.toArray());
s = s.substing(1, s.length()-1);// [] are guaranteed to be there

Das ist ziemlich seltsam, da es nur für Zahlen funktioniert, die SQL-Daten ähneln.

1
xss

Obwohl ich denke, dass Sie am besten Joiner von Guava verwenden, finde ich diesen Ansatz eleganter, wenn ich ihn von Hand codiere als das 'erste' Flag oder das abhackende letzte Komma.

private String commas(Iterable<String> strings) {
    StringBuilder buffer = new StringBuilder();
    Iterator<String> it = strings.iterator();
    if (it.hasNext()) {
        buffer.append(it.next());
        while (it.hasNext()) {
            buffer.append(',');
            buffer.append(it.next());
        }
    }

    return buffer.toString();
}
1
Victor

Das Schöne am IN-Ausdruck ist, dass bei wiederholten Werten das Ergebnis nicht geändert wird. Also duplizieren Sie einfach das erste Element und verarbeiten Sie die gesamte Liste. Dies setzt voraus, dass mindestens ein Element in der Liste vorhanden ist. Wenn es keine Elemente gibt, würde ich vorschlagen, zuerst danach zu suchen und dann die SQL überhaupt nicht auszuführen.

Dies macht den Trick, ist offensichtlich in dem, was es tut, und stützt sich nicht auf irgendwelche externen Bibliotheken:

StringBuffer inString = new StringBuffer(listOfIDs.get(0).toString());
for (Long currentID : listOfIDs) {
  inString.append(",").append(currentID);
}
1
VIM

Möglicherweise können Sie LINQ (to SQL) und das Dynamic Query LINQ-Beispiel von MS verwenden. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

0
GregUzelac

Listentoken = new ArrayList (Ergebnis); final StringBuilder builder = new StringBuilder ();

    for (int i =0; i < tokens.size(); i++){
        builder.append(tokens.get(i));
        if(i != tokens.size()-1){
            builder.append(TOKEN_DELIMITER);
        }
    }

builder.toString ();

0
Ups

Der einfachste Weg in Android für die Konvertierung von List in Comma Separated String ist die Verwendung von Android.text.TextUtils

 ArrayList<String>Myli = new ArrayList<String>();
 String ArayCommase=Android.text.TextUtils.join(",", Myli);
0
Jayman Jani

Es gibt einen einfachen Weg. Sie können Ihr Ergebnis in einer einzigen Zeile erhalten.

String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")");

Um eine vollständige Vorstellung zu erhalten, überprüfen Sie den folgenden Code

 public static void main(String[] args) {       
        List<Integer>memberIds=new ArrayList<Integer>();  //This contain member ids we want to process
        //adding some sample values for example
        memberIds.add(3); 
        memberIds.add(4);
        memberIds.add(2);
        String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")"); //here you will get (3,4,5) That you can directly use in query
        System.out.println(memberIdsModifiedForQuery);
        String exampleQuery="select * from customer where customer.id in "+memberIdsModifiedForQuery+" ";
    }
0
Fathah Rehman P
String commaSeparatedNames = namesList.toString().replaceAll( "[\\[|\\]| ]", "" );  // replace [ or ] or blank

Die Zeichenfolgendarstellung besteht aus einer Liste der Elemente der Auflistung in der Reihenfolge, in der sie von ihrem Iterator zurückgegeben werden, eingeschlossen in eckigen Klammern ("[]"). Angrenzende Elemente werden durch die Zeichen "," (Komma und Leerzeichen) getrennt.

AbstractCollection javadoc

0
Todd Gatts
Java.util.List<String> lista = new Java.util.ArrayList<String>();
lista.add("Hola");
lista.add("Julio");
System.out.println(lista.toString().replace('[','(').replace(']',')'));

$~(Hola, Julio)
0
Julio César