Быстрый и простой способ объединения элементов массива с разделителем (противоположность разбиению) в Java
Я ищу быстрый и простой способ сделать в точности противоположность разбиению, чтобы это ["a","b","c"]
становиться "a,b,c"
Итерация по массиву требует либо добавления условия (если это не последний элемент, добавьте разделитель), либо использования подстроки для удаления последнего разделителя.
Я уверен, что есть сертифицированный, эффективный способ сделать это (Apache Commons?)
Как вы предпочитаете делать это в своих проектах?
15 ответов
Используя Java 8, вы можете сделать это очень простым способом:
String.join(delimiter, elements);
Это работает тремя способами:
1) непосредственное указание элементов
String joined1 = String.join(",", "a", "b", "c");
2) использование массивов
String[] array = new String[] { "a", "b", "c" };
String joined2 = String.join(",", array);
3) использование итераций
List<String> list = Arrays.asList(array);
String joined3 = String.join(",", list);
Если вы на Android, вы можете TextUtils.join(delimiter, tokens)
Я предпочитаю Коллекции Google над Apache StringUtils для этой конкретной проблемы:
Joiner.on(separator).join(array)
По сравнению со StringUtils, Joiner API имеет гибкий дизайн и немного более гибок, например, null
элементы могут быть пропущены или заменены заполнителем. Также, Joiner
имеет функцию для соединения карт с разделителем между ключом и значением.
Apache Commons Lang действительно имеет StringUtils.join
метод, который подключит String
массивы вместе с указанным разделителем.
Например:
String[] s = new String[] {"a", "b", "c"};
String joined = StringUtils.join(s, ","); // "a,b,c"
Однако я подозреваю, что, как вы упоминаете, в реальной реализации вышеупомянутого метода должна быть какая-то условная обработка или обработка подстрок.
Если бы я должен был выполнить String
присоединяясь и не имея других причин использовать Commons Lang, я бы, вероятно, выбрал свою собственную, чтобы уменьшить количество зависимостей от внешних библиотек.
Быстрое и простое решение без участия третьих лиц.
public static String strJoin(String[] aArr, String sSep) {
StringBuilder sbStr = new StringBuilder();
for (int i = 0, il = aArr.length; i < il; i++) {
if (i > 0)
sbStr.append(sSep);
sbStr.append(aArr[i]);
}
return sbStr.toString();
}
В Java 1.8 появился новый класс StringJoiner, поэтому нет необходимости в Guava или Apache Commons:
String str = new StringJoiner(",").add("a").add("b").add("c").toString();
Или используя коллекцию напрямую с новым потоком API:
String str = Arrays.asList("a", "b", "c").stream().collect(Collectors.joining(","));
"Я уверен, что есть сертифицированный, эффективный способ сделать это (Apache Commons?)"
да, очевидно это
StringUtils.join(array, separator)
Еще проще, вы можете просто использовать массивы, так что вы получите строку со значениями массива, разделенными ","
String concat = Arrays.toString(myArray);
так что в итоге вы получите: concat = "[a,b,c]"
Обновить
Затем вы можете избавиться от скобок, используя подстроку, как предложено Джеффом
concat = concat.substring(1, concat.length() -1);
так что в итоге вы получите concat = "a,b,c"
Вы можете использовать replace и replaceAll с регулярными выражениями.
String[] strings = {"a", "b", "c"};
String result = Arrays.asList(strings).toString().replaceAll("(^\\[|\\]$)", "").replace(", ", ",");
Так как Arrays.asList().toString()
производит: "[a, b, c]", мы делаем replaceAll
чтобы удалить первые и последние скобки, а затем (необязательно) вы можете изменить "," последовательность для "," (ваш новый разделитель).
Раздетая версия (меньше символов):
String[] strings = {"a", "b", "c"};
String result = ("" + Arrays.asList(strings)).replaceAll("(^.|.$)", "").replace(", ", "," );
Регулярные выражения очень мощные, особенно методы String "replaceFirst" и "replaceAll". Дай им попробовать.
Все эти другие ответы включают в себя накладные расходы времени выполнения... например, использование ArrayList.toString(). ReplaceAll(...), которые очень расточительны.
Я дам вам оптимальный алгоритм с нулевыми накладными расходами; это выглядит не так красиво, как другие варианты, но внутренне это то, что они все делают (после кучек других скрытых проверок, выделения нескольких массивов и прочего типа "грязь").
Поскольку вы уже знаете, что имеете дело со строками, вы можете сохранить кучу распределений массивов, выполнив все вручную. Это нехорошо, но если вы проследите фактические вызовы методов, сделанные другими реализациями, вы увидите, что у него меньше всего накладных расходов во время выполнения.
public static String join(String separator, String ... values) {
if (values.length==0)return "";//need at least one element
//all string operations use a new array, so minimize all calls possible
char[] sep = separator.toCharArray();
// determine final size and normalize nulls
int totalSize = (values.length - 1) * sep.length;// separator size
for (int i = 0; i < values.length; i++) {
if (values[i] == null)
values[i] = "";
else
totalSize += values[i].length();
}
//exact size; no bounds checks or resizes
char[] joined = new char[totalSize];
int pos = 0;
//note, we are iterating all the elements except the last one
for (int i = 0, end = values.length-1; i < end; i++) {
System.arraycopy(values[i].toCharArray(), 0,
joined, pos, values[i].length());
pos += values[i].length();
System.arraycopy(sep, 0, joined, pos, sep.length);
pos += sep.length;
}
//now, add the last element;
//this is why we checked values.length == 0 off the hop
System.arraycopy(values[values.length-1].toCharArray(), 0,
joined, pos, values[values.length-1].length());
return new String(joined);
}
Эта маленькая функция всегда пригодится.
public static String join(String[] strings, int startIndex, String separator) {
StringBuffer sb = new StringBuffer();
for (int i=startIndex; i < strings.length; i++) {
if (i != startIndex) sb.append(separator);
sb.append(strings[i]);
}
return sb.toString();
}
Этот вариант быстрый и понятный:
public static String join(String separator, String... values) {
StringBuilder sb = new StringBuilder(128);
int end = 0;
for (String s : values) {
if (s != null) {
sb.append(s);
end = sb.length();
sb.append(separator);
}
}
return sb.substring(0, end);
}
Это в StringUtils:
Подход, который я использовал, развился со времени Java 1.0, чтобы обеспечить читабельность и поддерживать разумные параметры для обратной совместимости со старыми версиями Java, а также предоставлять сигнатуры методов, которые являются заменой для тех из Apache commons-lang. Из соображений производительности я вижу некоторые возможные возражения против использования Arrays.asList, но я предпочитаю вспомогательные методы, которые имеют разумные значения по умолчанию без дублирования одного метода, выполняющего реальную работу. Этот подход обеспечивает соответствующие точки входа в надежный метод, который не требует преобразования массива / списка перед вызовом.
Возможные варианты совместимости версий Java включают замену StringBuffer (Java 1.0) на StringBuilder (Java 1.5), отключение итератора Java 1.5 и удаление универсального подстановочного знака (Java 1.5) из коллекции (Java 1.2). Если вы хотите сделать обратную совместимость на шаг или два дальше, удалите методы, использующие Collection, и переместите логику в метод на основе массива.
public static String join(String[] values)
{
return join(values, ',');
}
public static String join(String[] values, char delimiter)
{
return join(Arrays.asList(values), String.valueOf(delimiter));
}
// To match Apache commons-lang: StringUtils.join(values, delimiter)
public static String join(String[] values, String delimiter)
{
return join(Arrays.asList(values), delimiter);
}
public static String join(Collection<?> values)
{
return join(values, ',');
}
public static String join(Collection<?> values, char delimiter)
{
return join(values, String.valueOf(delimiter));
}
public static String join(Collection<?> values, String delimiter)
{
if (values == null)
{
return new String();
}
StringBuffer strbuf = new StringBuffer();
boolean first = true;
for (Object value : values)
{
if (!first) { strbuf.append(delimiter); } else { first = false; }
strbuf.append(value.toString());
}
return strbuf.toString();
}
public String join(String[] str, String separator){
String retval = "";
for (String s: str){ retval+= separator + s;}
return retval.replaceFirst(separator, "");
}