Java: funkcja dla tablic takich jak PHP join ()?

Odpowiedzi:

307

Począwszy od Java8 można używać String.join().

String.join(", ", new String[]{"Hello", "World", "!"})

Generuje:

Hello, World, !

W przeciwnym razie Apache Commons Lang ma StringUtilsklasę, która ma joinfunkcję, która połączy tablice razem, aby utworzyć String.

Na przykład:

StringUtils.join(new String[] {"Hello", "World", "!"}, ", ")

Generuje następujące String:

Hello, World, !
coobird
źródło
7
Z korzyścią dla osób szukających tej odpowiedzi należy prawdopodobnie zauważyć, że jest to również odpowiednik połączenia Perla.
k-den
3
mówi, że jest dla mnie niezdefiniowany
Ninjaxor,
@Ninjaxor 1. jar commons-lang * musi znajdować się w ścieżce klasy 2. import org.apache.commons.lang3.StringUtils;
peterh - Przywróć Monikę
9
Polecam edycję tej odpowiedzi, aby dołączyć odniesienie do nowej String.join()metody wprowadzonej w Javie 8. W ten sposób ogromna liczba osób czytających tę zaakceptowaną odpowiedź skorzysta z tej wiedzy. Obecnie najwyżej głosowana odpowiedź na ten fakt jest raczej zagubiona poniżej ...
Duncan Jones
1
Warto wspomnieć, że String.join()będzie działać tylko na List<CharSequence>lub CharSequence[]elementy.
Enigo,
71

Jeśli szukasz tego, czego użyć w Androidzie, jest to:

String android.text.TextUtils.join(CharSequence delimiter, Object[] tokens)

na przykład:

String joined = TextUtils.join(";", MyStringArray);
Noah
źródło
2
Jest to zdecydowanie najlepsza odpowiedź dla wszystkich wersji Androida, ponieważ Java 8 pojawia się na Androida dopiero za chwilę. To rozwiązanie wykorzystuje wbudowane biblioteki systemu Android, a nie te głupie rozwiązania „obejmują ogromną bibliotekę do wykonania jednej akcji”.
LukeStoneHm
Jest wrzesień 2017, Java 8 dla Androida jest wciąż daleko. Dzięki za tę odpowiedź!
Aenadon
53

Możesz łatwo napisać taką funkcję w około dziesięciu wierszach kodu:

String combine(String[] s, String glue)
{
  int k = s.length;
  if ( k == 0 )
  {
    return null;
  }
  StringBuilder out = new StringBuilder();
  out.append( s[0] );
  for ( int x=1; x < k; ++x )
  {
    out.append(glue).append(s[x]);
  }
  return out.toString();
}
Sójka
źródło
35
Dobra praktyka według ciebie ... nie ma uniwersalnego standardu dla takich rzeczy.
phoebus
24
Gdybym jednak dodał nawiasy klamrowe, dodałbym jeszcze dwa wiersze kodu i nie mogłem twierdzić, że zrobiłem to w 11 wierszach!
Jay
8
problem polega na tym, że po chwili lub w pośpiechu dodajesz kolejną linię, jeśli / bez dodawania nawiasów klamrowych; lub usuń return null po if (k == 0), który w niektórych przypadkach skompiluje się, ale będzie niepoprawny. Następnie lepiej poświęcić jedną dodatkową linię dla tej klamry zamykającej (otwarcie może pozostać w tej samej linii jeśli / dla).
Mediolan
16
Myślę, że to niesamowite, że chociaż większość języków ma taką funkcjonalność w swoim rdzeniu, społeczność Java zachęca wszystkich do ponownego odkrycia koła.
John Strickler,
33
11 linii? Bah! Mogę to zrobić w 1! Po prostu usuń wszystkie znaki nowego wiersza z pliku źródłowego.
Thomas Eding,
25

Mały mod zamiast używać substring ():

//join(String array,delimiter)
public static String join(String r[],String d)
{
        if (r.length == 0) return "";
        StringBuilder sb = new StringBuilder();
        int i;
        for(i=0;i<r.length-1;i++){
            sb.append(r[i]);
            sb.append(d);
        }
        sb.append(r[i]);
        return sb.toString();
}
everlasto
źródło
Zagłosowano, ponieważ nie trzeba dodawać żadnej biblioteki.
ofiaruje
10
Wiersz 7: Czy lepiej byłoby użyć go .append()dwa razy dla każdego Stringzamiast połączyć je, a następnie dołączyć do konstruktora.
Talha Ahmed Khan
18

Jak w przypadku wielu pytań ostatnio, Java 8 na ratunek:


Java 8 dodała nową metodę statyczną, java.lang.Stringktóra robi dokładnie to, co chcesz:

public static String join(CharSequence delimeter, CharSequence... elements);

Użyj tego:

String s = String.join(", ", new String[] {"Hello", "World", "!"});

Prowadzi do:

"Hello, World, !"
icza
źródło
14

Biblioteka Google guava ma również tego rodzaju możliwości . Możesz zobaczyć przykład String [] również z API.

Jak już opisano w interfejsie API, strzeż się niezmienności metod konstruktora.

Może przyjmować tablicę obiektów, więc będzie działać w twoim przypadku. W poprzednim doświadczeniu próbowałem dołączyć do stosu, który jest iterowalny i działa dobrze.

Próbka ode mnie:

Deque<String> nameStack = new ArrayDeque<>();
nameStack.push("a coder");
nameStack.push("i am");
System.out.println("|" + Joiner.on(' ').skipNulls().join(nameStack) + "|");

drukuje: |i am a coder|

Bertie
źródło
9

Dany:

String[] a = new String[] { "Hello", "World", "!" };

Następnie jako alternatywa dla odpowiedzi Coobirda, gdzie klejem jest „,”:

Arrays.asList(a).toString().replaceAll("^\\[|\\]$", "")

Lub połączyć z innym ciągiem, takim jak „& amp;”.

Arrays.asList(a).toString().replaceAll(", ", " &amp; ").replaceAll("^\\[|\\]$", "")

Jednak ... ten działa TYLKO, jeśli wiesz, że wartości w tablicy lub liście NIE zawierają ciągu znaków „,”.

Rob w TVSeries.com
źródło
Arrays.asList(a).toString()pracował dla tego, co chciałem zrobić
Solomon Ucko
9

Jeśli używasz Spring Framework , masz klasę StringUtils :

import static org.springframework.util.StringUtils.arrayToDelimitedString;

arrayToDelimitedString(new String[] {"A", "B", "C"}, "\n");
devstopfix
źródło
8

Nie w rdzeniu, nie. Poszukiwanie „kleju do łączenia łańcuchów java” da ci kilka fragmentów kodu, jak to osiągnąć.

na przykład

public static String join(Collection s, String delimiter) {
    StringBuffer buffer = new StringBuffer();
    Iterator iter = s.iterator();
    while (iter.hasNext()) {
        buffer.append(iter.next());
        if (iter.hasNext()) {
            buffer.append(delimiter);
        }
    }
    return buffer.toString();
}

źródło
2
Użyj StringBuilder (nie bezpieczny dla wątków) zamiast StringBuffer (bezpieczny dla wątków) dla lepszej wydajności. Interfejs jest taki sam.
Asaph
2
Wygląda na to, że pochodzi z snippets.dzone.com/posts/show/91 . Komentarze sugerują znacznie ulepszoną wersję: publiczne statyczne łączenie ciągów (Iterable <? Extends Object> pColl, separator ciągów) {Iterator <? rozszerza Obiekt> oIter; if (pColl == null || (! (oIter = pColl.iterator ()) .hasNext ())) return ""; StringBuilder oBuilder = new StringBuilder (String.valueOf (oIter.next ())); while (oIter.hasNext ()) oBuilder.append (separator) .append (oIter.next ()); return oBuilder.toString (); }
Quantum7,
6

Jeśli wylądowałeś tutaj, szukając szybkiej konwersji tablic na ciąg, wypróbuj Arrays.toString () .

Tworzy ciąg reprezentujący Object[]przekazane. Wynik jest otoczony nawiasami kwadratowymi ( "[]"), każdy element jest konwertowany na ciąg znaków przez String.valueOf(Object)i oddzielany przez ", ". Jeśli tablica jest null, to "null"jest zwracana.

miętówka
źródło
DZIĘKUJĘ BARDZO! Ciągi znaków są oddzielone „,”, a cała rzecz ma wokół siebie „[]”, co jest dla mnie w porządku.
John Henckel
5

Tylko dla wyzwania „Mam najkrótszy” , oto kopalnie;)

Wielokrotny:

public static String join(String s, Object... a) {
    StringBuilder o = new StringBuilder();
    for (Iterator<Object> i = Arrays.asList(a).iterator(); i.hasNext();)
        o.append(i.next()).append(i.hasNext() ? s : "");
    return o.toString();
}

Rekurencyjne:

public static String join(String s, Object... a) {
    return a.length == 0 ? "" : a[0] + (a.length == 1 ? "" : s + join(s, Arrays.copyOfRange(a, 1, a.length)));
}
sp00m
źródło
2
Wersja rekurencyjna jest elegancka. Zdecydowanie zamierzam z tego skorzystać.
Pete,
Wersja rekurencyjna może być elegancka, ale nieefektywna w przypadku dużych tablic („ copyOfRange()”).
Ogre Psalm33
4

Tak to robię.

private String join(String[] input, String delimiter)
{
    StringBuilder sb = new StringBuilder();
    for(String value : input)
    {
        sb.append(value);
        sb.append(delimiter);
    }
    int length = sb.length();
    if(length > 0)
    {
        // Remove the extra delimiter
        sb.setLength(length - delimiter.length());
    }
    return sb.toString();
}
Richard Corfield
źródło
2

Podobna alternatywa

/**
 * @param delimiter 
 * @param inStr
 * @return String
 */
public static String join(String delimiter, String... inStr)
{
    StringBuilder sb = new StringBuilder();
    if (inStr.length > 0)
    {
        sb.append(inStr[0]);
        for (int i = 1; i < inStr.length; i++)
        {
            sb.append(delimiter);                   
            sb.append(inStr[i]);
        }
    }
    return sb.toString();
}
William Simpson
źródło
2

Mój obrót.

public static String join(Object[] objects, String delimiter) {
  if (objects.length == 0) {
    return "";
  }
  int capacityGuess = (objects.length * objects[0].toString().length())
      + ((objects.length - 1) * delimiter.length());
  StringBuilder ret = new StringBuilder(capacityGuess);
  ret.append(objects[0]);
  for (int i = 1; i < objects.length; i++) {
    ret.append(delimiter);
    ret.append(objects[i]);
  }
  return ret.toString();
}

public static String join(Object... objects) {
  return join(objects, "");
}
Jackson
źródło
1

Czy podoba Ci się mój sposób 3-liniowy przy użyciu tylko metod klasy String?

static String join(String glue, String[] array) {
    String line = "";
    for (String s : array) line += s + glue;
    return (array.length == 0) ? line : line.substring(0, line.length() - glue.length());
}
Ryoichiro Oka
źródło
1
To nie ma być wydajne. Użyj, StringBuilderjeśli potrzebujesz wydajności: P
Ryoichiro Oka
0

Aby uzyskać „str1, str2” z „str1”, „str2”, „”:

Stream.of("str1", "str2", "").filter(str -> !str.isEmpty()).collect(Collectors.joining(", ")); 

Możesz także dodać dodatkową kontrolę zerową

ema
źródło
0

Jeśli korzystasz z biblioteki Functional Java i z jakiegoś powodu nie możesz używać strumieni z Java 8 (co może mieć miejsce w przypadku korzystania z wtyczki Android + Retrolambda), oto funkcjonalne rozwiązanie dla Ciebie:

String joinWithSeparator(List<String> items, String separator) {
    return items
            .bind(id -> list(separator, id))
            .drop(1)
            .foldLeft(
                    (result, item) -> result + item,
                    ""
            );
}

Pamiętaj, że nie jest to najbardziej wydajne podejście, ale działa dobrze w przypadku małych list.

Dmitrij Zajcew
źródło
-1

Robię to w ten sposób za pomocą StringBuilder:

public static String join(String[] source, String delimiter) {
    if ((null == source) || (source.length < 1)) {
        return "";
    }

    StringBuilder stringbuilder = new StringBuilder();
    for (String s : source) {
        stringbuilder.append(s + delimiter);
    }
    return stringbuilder.toString();
} // join((String[], String)
spanky762
źródło
1
s + delimiter(konkatenacja ciągów z operatorem plusa) pokonuje cały cel używania StringBuilder.
quietmint
Ponadto takie podejście oznaczałoby, że tablica taka jak: {„foo”, „bar”} z ogranicznikiem „:” zamieniłaby się w „foo: bar:”
pioto
-2

Jest to prosta technika stenografii, z której najczęściej korzystam.

String op = new String;
for (int i : is) 
{
    op += candidatesArr[i-1]+",";
}
op = op.substring(0, op.length()-1);
Gaurav Adurkar
źródło
Działa to tylko z ogranicznikami długości 1 i wymaga „magicznych liczb” (choć dość lokalnych), jeśli chcesz ogranicznik o innej długości.
maiwald
Możesz dodać wiele postaci podczas dołączania
Gaurav Adurkar
niż po prostu wykonaj: op = op.substring (0, op.length () - ",". length ()); o co tyle szumu?
Dennis
-3

java.util.Arrays ma metodę „asList”. W połączeniu z interfejsem API java.util.List / ArrayList zapewnia to wszystko, czego potrzebujesz :;

private static String[] join(String[] array1, String[] array2) {

    List<String> list = new ArrayList<String>(Arrays.asList(array1));
    list.addAll(Arrays.asList(array2));
    return list.toArray(new String[0]);
}
Adriaan Koster
źródło
7
Pytanie brzmi: jak połączyć tablicę ciągów z separatorem, a nie jak połączyć dwie tablice ciągów razem.
toolbear