Java-Äquivalent zum implodierten PHP (',', array_filter (array ()))

75

Ich benutze diesen Code oft in PHP

$ordine['address'] = implode(', ', array_filter(array($cliente['cap'], $cliente['citta'], $cliente['provincia'])));

Es löscht leere Zeichenfolgen und verbindet sie mit einem ",". Wenn nur noch eines übrig bleibt, wird kein zusätzliches nicht benötigtes Komma hinzugefügt. Am Ende wird kein Komma hinzugefügt. Wenn keine übrig bleibt, wird eine leere Zeichenfolge zurückgegeben.

Somit kann ich eines der folgenden Ergebnisse erhalten

""
"Street abc 14"
"Street abc 14, 00168"
"Street abc 14, 00168, Rome"

Was ist die beste Java-Implementierung (weniger Code) in Java, ohne dass externe Bibliotheken hinzugefügt werden müssen (Design für Android)?

max4ever
quelle
Zu Ihrer Information, für dieses Beispiel benötigen Sie eine externe Bibliothek (import org.apache.commons.lang.StringUtils;), aber ich würde trotzdem empfehlen, diese Methode zu verwenden
Owen Gerig
dfreeman macht nicht was ich brauche, kein Komma hinzufügen wo nötig
max4ever
4
Ich kann nicht glauben, dass Java dies noch nicht eingebaut hat. jede andere Sprache tut es.
OneSolitaryNoob
Können Sie bitte die Akzeptanzmarke ändern? stackoverflow.com/a/11248692/871050 Diese Antwort ist hier die richtigste.
Madaras Geist

Antworten:

89

Aktualisierte Version mit Java 8 (Original am Ende des Beitrags)

Wenn Sie keine Elemente filtern müssen, können Sie diese verwenden


Seit Java 8 können wir unseren Code verwenden StringJoiner(anstatt ursprünglich verwendet StringBulder) und vereinfachen.
Um zu vermeiden, dass " *"Regex bei jedem Aufruf von neu kompiliert wird, matches(" *")können wir ein separates Muster erstellen, das die kompilierte Version in einem bestimmten Feld enthält und bei Bedarf verwendet.

private static final Pattern SPACES_OR_EMPTY = Pattern.compile(" *");
public static String implode(String separator, String... data) {
    StringJoiner sb = new StringJoiner(separator);
    for (String token : data) {
        if (!SPACES_OR_EMPTY.matcher(token).matches()) {
            sb.add(token);
        }
    }
    return sb.toString();
}   

Bei Streams kann unser Code so aussehen.

private static final Predicate<String> IS_NOT_SPACES_ONLY = 
        Pattern.compile("^\\s*$").asPredicate().negate();

public static String implode(String delimiter, String... data) {
    return Arrays.stream(data)
            .filter(IS_NOT_SPACES_ONLY)
            .collect(Collectors.joining(delimiter));
}

Wenn wir Streams verwenden, können wir filterElemente, die Predicate. In diesem Fall möchten wir, dass das Prädikat Zeichenfolgen akzeptiert, die nicht nur Leerzeichen sind. Mit anderen Worten, Zeichenfolgen müssen Nicht-Leerzeichen enthalten.

Wir können ein solches Prädikat aus dem Muster erstellen. Prädikats erstellt diese Art und Weise werden alle Strings akzeptieren , die Zeichenkette enthalten wird , die durch regex abgestimmt werden (also wenn regex für aussehen "\\S"Prädikat wird Strings wie akzeptieren "foo ", " foo bar ", "whatever", aber nicht akzeptieren " "noch " ").

Also können wir verwenden

Pattern.compile("\\S").asPredicate();

oder möglicherweise etwas aussagekräftiger, Negation von Zeichenfolgen, die nur Leerzeichen oder leer sind

Pattern.compile("^\\s*$").asPredicate().negate();

Wenn der Filter alle leeren oder nur Leerzeichen enthaltenden Zeichenfolgen entfernt, können wir die collectrestlichen Elemente entfernen . Dank Collectors.joiningkönnen wir entscheiden, welches Trennzeichen verwendet werden soll.


Ursprüngliche Antwort (vor Java 8)

public static String implode(String separator, String... data) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.length - 1; i++) {
    //data.length - 1 => to not add separator at the end
        if (!data[i].matches(" *")) {//empty string are ""; " "; "  "; and so on
            sb.append(data[i]);
            sb.append(separator);
        }
    }
    sb.append(data[data.length - 1].trim());
    return sb.toString();
}

Sie können es wie verwenden

System.out.println(implode(", ", "ab", " ", "abs"));

oder

System.out.println(implode(", ", new String[] { "ab", " ", "abs" }));

Ausgabe ab, abs

Pshemo
quelle
Ja, es ist komfortabler zu verwenden, da Sie kein Array erstellen müssen, und ich wusste nicht, dass Sie String, String ...
max4ever
es funktioniert nicht gut, wenn Daten eine Länge von 1 xD haben. Ich benutze dieses sb.append (data [0]); für (int i = 1; i <(data.length); i ++) {//data.length - 1 =>, um am Ende kein Trennzeichen hinzuzufügen, wenn ((data [i]! = null) &&! data [i ] .matches ("*")) {// leere Zeichenfolge sind ""; ""; ""; und so weiter sb.append (Trennzeichen); sb.append (Daten [i]); }}
max4ever
1
@ max4ever könntest du ein Beispiel zeigen? Ich habe an getestet System.out.println(implode(", ", "X"))und es scheint gut zu funktionieren.
Pshemo
79

Warum so ernst? Versuchen Sie es StringUtils.join(new String[] {"Hello", "World", "!"}, ", ")!

Bogdan Burym
quelle
30
StringUtils ist eine externe Bibliothek
max4ever
28
Es wurde von Apache hergestellt, jeder benutzt es ... Ich mache es Bogdans Art, ihr macht was ihr wollt
anton1980
10
Es ist in Ordnung, dass Sie "es auf Ihre Weise tun", wenn die Bibliothek bereits verfügbar ist. Wenn nicht, a) müssen Sie wissen, dass es sich um ein externes handelt, b) wo / wie Sie es erhalten können und c) ob Sie dazu berechtigt sind. Das Spielen eines nicht korporativen Cowboys entlastet Sie nur von c)
Zefiro
3
Die externe Bibliothek finden Sie hier: commons.apache.org/proper/commons-lang
Alan B. Dee
18

Hier ist eine Android-spezifische Antwort, die für einige hilfreich sein kann:

String combined = TextUtils.join(",", new String[]{"Red", "Green", "Blue"});

// Result => Red,Green,Blue

Stellen Sie sicher, dass Sie die TextUtils-Klasse importieren:

import android.text.TextUtils;
dloomb
quelle
17

Sie müssten Ihre Zeichenfolgen zu einer ArrayList hinzufügen, leere entfernen und entsprechend formatieren:

public static String createAddressString( String street, String zip_code, String country) {
    List<String> list = new ArrayList<String>();
    list.add( street);
    list.add( zip_code);
    list.add( country);

    // Remove all empty values
    list.removeAll(Arrays.asList("", null));

    // If this list is empty, it only contained blank values
    if( list.isEmpty()) {
        return "";
    }

    // Format the ArrayList as a string, similar to implode
    StringBuilder builder = new StringBuilder();
    builder.append( list.remove(0));

    for( String s : list) {
        builder.append( ", ");
        builder.append( s);
    }

    return builder.toString();
}

Wenn Sie über String[]ein Array von Zeichenfolgen verfügen, können Sie diese außerdem einfach zu einer ArrayList hinzufügen:

String[] s;
List<String> list = new ArrayList<String>( Arrays.asList( s));
Nickb
quelle
In einer Implementierung der implodierten Funktion ändern Sie die ursprüngliche Liste (falsch) und entfernen das erste Element von ArrayList (teuer). Auch die vorgeschlagene Transformation vom Array - warum nicht einfach asList? Wenn es sich bei der Eingabe um eine Liste handelt, ist es wahrscheinlich am saubersten, den Iterator der Liste zu verwenden, indem der erste Elementvorzyklus gelesen (und angehängt) und der Rest iteriert wird. Entschuldigung, aber ich muss dir -1 geben.
Vlasec
Zum Entfernen von Nullen und leeren Zeichenfolgen können Sie diese auch aus der Ausgabe entfernen, ohne die ursprüngliche Liste zu ändern. Sie benötigen jedoch einen Zyklus zum Auffinden des ersten nicht leeren Elements und kein einfaches if. Außerdem schlägt Ihre Lösung in einer leeren Liste fehl - remove(0)wirft eine IndexOutOfBoundsException.
Vlasec
@Vlasec - Es gibt keine Originalliste innerhalb der Methode, mit der ich meine eigene lokale Liste erstelle. Daher ist Ihr Argument ungültig, da die Eingabe keine Liste ist, sondern die drei Zeichenfolgenwerte. Außerdem wird überprüft, ob die Liste leer ist. Dies ist ein weiteres ungültiges Argument, das Sie angegeben haben.
Nickb
Sie sind technisch korrekt. Sie sollten dennoch versuchen, hier die Best Practices zu vermitteln. Einige Greenhorn könnten Ihre Technik übernehmen und eine vorhandene Liste durcheinander bringen. Außerdem ist dies kein besonders effektiver oder eleganter Ansatz, selbst wenn Sie die Sammlung zerstören können.
Vlasec
@Vlasec - Sie haben ein Recht auf Ihre Meinung, aber ich bin anderer Meinung. Ihr Kommentar, dass es sich nicht um eine effektive oder elegante Lösung handelt, basiert ausschließlich auf der Meinung.
Nickb
2

Ein einfaches Implodieren

public static String implode(String glue, String[] strArray)
{
    String ret = "";
    for(int i=0;i<strArray.length;i++)
    {
        ret += (i == strArray.length - 1) ? strArray[i] : strArray[i] + glue;
    }
    return ret;
}

Sie können dafür Überladungen erstellen.

Das obige Äquivalent von PHP implodiert.
Folgendes möchten Sie:

import java.lang.*
public static String customImplode(String glue, String[] strArray)
{
    String ret = "";
    for(int i=0;i<strArray.length;i++)
    {
        if (strArray[i].trim() != "")
            ret += (i == strArray.length - 1) ? strArray[i] : strArray[i] + glue;
    }
    return ret;
}
Soroush Khosravi
quelle
2
es fügt Kleber am Ende hinzu, und es überspringt keine leeren Zeichenfolgen
max4ever
@ max4ever ich denke das ist deine Antwort, nicht wahr?
Soroush Khosravi
Überspringt immer noch keine leeren Zeichenfolgen
max4ever
@ max4ever Bitte klären Sie Ihre Frage. Sie wollen eine benutzerdefinierte Methode oder ein Äquivalent von PHP implodieren ?! \
Soroush Khosravi
Sie müssen ein (TextUtils.isEmpty (strArray [i]) hinzufügen? "": strArray [i] + Kleber, damit es funktioniert
max4ever
2

Die Verwendung von Streams (für Java 8 und höher) wäre hierfür eine alternative mögliche Lösung.

Sie müssen importieren

java.util.stream.Collectors;

um den Join-Prozess zu verwenden

Sie können verwenden:

Arrays.asList("foo","bar").stream().collect(Collectors.joining(","));

um das gewünschte Ergebnis zu erzielen.

Aman J.
quelle
1

Hier ist meine implodierende Implementierung:

/**
 * Implodes the specified items, gluing them using the specified glue replacing nulls with the specified
 * null placeholder.
 * @param glue              The text to use between the specified items.
 * @param nullPlaceholder   The placeholder to use for items that are <code>null</code> value.
 * @param items             The items to implode.
 * @return  A <code>String</code> containing the items in their order, separated by the specified glue.
 */
public static final String implode(String glue, String nullPlaceholder, String ... items) {
    StringBuilder sb = new StringBuilder();
    for (String item : items) {
        if (item != null) {
            sb.append(item);
        } else {
            sb.append(nullPlaceholder);
        }
        sb.append(glue);
    }
    return sb.delete(sb.length() - glue.length(), sb.length()).toString();
}
Ben Barkay
quelle
1
public static String implode(List<String> items, String separator) {

        if (items == null || items.isEmpty()) {
            return null;
        }
        String delimiter = "";
        StringBuilder builder = new StringBuilder();
        for (String item : items) {
            builder.append(delimiter).append(item);
            delimiter = separator;
        }
        return builder.toString();
    }
Ahmad
quelle
Eine Erklärung wäre angebracht.
Peter Mortensen
0

Verwenden Sie diese einfache Funktion:

private String my_implode(String spacer, String[] in_array){

    String res = "";

    for (int i = 0 ; i < in_array.length ; i++) {

        if (!res.equals("")) {
            res += spacer;
        }
        res += in_array[i];
    }

    return res;
}

Verwenden:

data_arr = {"d1", "d2", "d3"};
your_imploded_text = my_implode(",", data_arr);
// Output: your_imploded_text = "d1,d2,d3"
Ferhad Konar
quelle