Java: функція для масивів, як PHP join ()?


259

Я хочу приєднатись String[]до клею. Чи є для цього функція?


7
У Java 8 ця функціональність включена поза коробкою. Я рекомендую читачеві перегорнути до відповіді по @Marek Грегора (і upvote це ..)
Stav

Відповіді:


307

Починаючи з Java8 можна користуватися String.join().

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

Створює:

Hello, World, !

В іншому випадку Apache Commons Lang має StringUtilsклас, який має joinфункцію, яка з'єднає масиви разом, щоб скласти а String.

Наприклад:

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

Створює таке String:

Hello, World, !

7
Для користі людей, які шукають цю відповідь, мабуть, слід зазначити, що це також еквівалент приєднання Perl.
k-den

3
там сказано, що для мене це не визначено
Ninjaxor

@Ninjaxor 1. commons-lang * jar має бути на classpath 2. імпорту org.apache.commons.lang3.StringUtils;
петерх

9
Я рекомендую вам відредагувати цю відповідь, щоб додати посилання на новий String.join()метод, запроваджений на Java 8. Таким чином, величезна кількість людей, які читають цю прийняту відповідь, отримають користь від цих знань. На даний момент найвища відповідь, що згадує цей факт, досить втрачена нижче ...
Дункан Джонс

1
Варто згадати, що String.join()працювало б лише для List<CharSequence>або CharSequence[]елементів.
Еніго

71

Якщо ви шукали, що використовувати в android, це:

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

наприклад:

String joined = TextUtils.join(";", MyStringArray);

2
Це, очевидно, найкраща відповідь для всіх версій Android, оскільки Java 8 на Android виходить лише трохи. Це рішення використовує вбудовані в Android libs, а не ці дурні "включають величезну ліб для виконання однієї дії".
LukeStoneHm

Вересень 2017 року, Java 8 для Android ще далеко. Дякую за цю відповідь!
Енадон


53

Ви можете легко записати таку функцію приблизно в десяти рядках коду:

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

35
Належна практика, на вашу думку ... немає універсального стандарту для таких речей.
фоеб

24
Але якби я включив дужки, це додало б ще два рядки коду, і я не міг би стверджувати, що робив це в 11 рядках!
Jay

8
проблема полягає в тому, коли ви через деякий час або хтось інший поспішаєте додати ще один рядок до цього, якщо / для, не додаючи дужки; або видалити return null після if (k == 0), який у деяких випадках компілюється, але буде неправильним. Тоді краще пожертвувати однією додатковою лінією для цієї закриваючої дужки (отвір може залишитися в тому ж, якщо / для лінії).
мілан

16
Я думаю, що дивним є той факт, що, хоча більшість мов пакують таку функціональність у своїй основі, спільнота Java закликає всіх винаходити колесо.
Джон Стріклер

33
11 рядків? Ба! Я можу це зробити за 1! Просто видаліть усі символи нового рядка у вихідному файлі.
Thomas Eding

25

Маленький мод замість використання 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();
}

Голосували, оскільки не потрібно додавати жодну бібліотеку
givanse

10
Рядок 7: Чи краще, якщо використовувати .append()два рази для кожного, Stringа не об'єднати їх, а потім додати до будівельника.
Талха Ахмед Хан

18

Як і багато запитань останнім часом, на допомогу Java 8:


Java 8 додала новий статичний метод, java.lang.Stringякий робить саме те, що ви хочете:

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

Використовуючи його:

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

Призводить до:

"Hello, World, !"

14

Бібліотека Google guava також має такі можливості . Ви можете побачити приклад String [] також з API.

Як уже описано в api, остерігайтеся незмінності будівельних методів.

Він може приймати масив об'єктів, щоб він працював у вашому випадку. У своєму попередньому досвіді я намагався приєднатись до Stack, який є ітерабельним, і він працює чудово.

Зразок від мене:

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

роздруковує: |i am a coder|


9

Подано:

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

Тоді як альтернатива відповіді coobird, де клей ",":

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

Або об'єднатися з іншим рядком, наприклад "& amp;".

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

Однак ... цей ТОЛЬКО працює, якщо ви знаєте, що значення масиву чи списку НЕ містять символьну рядок ",".


Arrays.asList(a).toString()працював над тим, що я хотів зробити
Соломон Учко

9

Якщо ви використовуєте Spring Framework, то у вас є клас StringUtils :

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

arrayToDelimitedString(new String[] {"A", "B", "C"}, "\n");

8

Не в основі, ні. Пошук "клей для об'єднання рядків java array" дасть вам кілька фрагментів коду, як цього досягти.

напр

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

2
Використовуйте StringBuilder (без потоку) замість StringBuffer (безпечно для потоків) для кращої роботи. Інтерфейс той самий.
Асаф

2
Це здається з snippets.dzone.com/posts/show/91 . У коментарях пропонується значно вдосконалена версія: загальнодоступний статичний рядок String (Iterable <? Extends Object> pColl, String separator) {Iterator <? розширює Object> oIter; якщо (pColl == null || (! (oIter = pColl.iterator ()) .hasNext ())) повернути ""; StringBuilder oBuilder = новий StringBuilder (String.valueOf (oIter.next ())); while (oIter.hasNext ()) oBuilder.append (separator) .append (oIter.next ()); повернути oBuilder.toString (); }
Quantum7

6

Якщо ви приземлилися тут, шукаючи швидкого перетворення рядка в рядок, спробуйте Arrays.toString () .

Створює рядкове представлення Object[]пройденого. Результат оточений дужками ( "[]"), кожен елемент перетворюється в String через String.valueOf(Object)і розділяється ", ". Якщо масив є null, то "null"повертається.


ДУЖЕ ДЯКУЮ! Рядки розділені ",", і вся річ має "[]" навколо себе, що добре зі мною.
Джон Генкель

5

Тільки для виклику "Я найкоротший" , ось міни;)

Ітеративний:

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

Рекурсивна:

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

2
Рекурсивна версія елегантна. Однозначно збираюся цим скористатися.
Піт

Рекурсивна версія може бути елегантною, але неефективною для великих масивів (" copyOfRange()").
Псалом Огре3333

4

Нічого вбудованого, що я знаю.

Apache Commons Lang має клас, StringUtilsякий називається, який містить багато функцій приєднання.


4

Ось як я це роблю.

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

2

Аналогічна альтернатива

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

2

Моє віджимання.

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, "");
}

1

Вам подобається мій 3-рядовий спосіб, використовуючи лише методи класу 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());
}

1
Це не повинно бути ефективним. Використовуйте, StringBuilderякщо вам потрібна ефективність: P
Ryoichiro Oka

0

Щоб отримати "str1, str2" з "str1", "str2", "":

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

Також ви можете додати додаткову нульову перевірку


0

Якщо ви використовуєте функціональну бібліотеку Java і чомусь не можете використовувати потоки з Java 8 (що може бути у випадку використання плагіна Android + Retrolambda), ось вам функціональне рішення:

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

Зауважте, що це не найефективніший підхід, але він працює добре для невеликих списків.


-1

Я роблю це так, використовуючи 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)

1
s + delimiter(об'єднання рядків з оператором плюс) перемагає цілі використання a StringBuilder.
тихість

Плюс цей підхід означав би, що масив на зразок: {"foo", "bar"} з роздільником ":" буде перетворений на "foo: bar:"
pioto

-2

Існує проста методика скорочення, яку я використовую більшість разів ..

String op = new String;
for (int i : is) 
{
    op += candidatesArr[i-1]+",";
}
op = op.substring(0, op.length()-1);

Це працює лише з роздільниками довжини 1 і вимагає "магічних чисел" (хоча і досить локальних), якщо ви хочете роздільник різної довжини.
maiwald

Ви можете додати кілька символів під час додавання
Gaurav Adurkar

ніж просто робити: op = op.substring (0, op.length () - ",". length ()); у чому велика справа?
Денніс

-3

java.util.Arrays має метод "asList". Разом з API java.util.List / ArrayList це дає вам все необхідне :;

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

7
Питання полягає в тому, як з'єднати масив рядків з роздільником, а не як з'єднати два масиви рядків разом.
інструментарій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.