Java: ¿función para matrices como join () de PHP?


259

Quiero unirme String[]con una cadena de pegamento. ¿Hay una función para esto?


77
Java 8 tiene esta funcionalidad incluida de fábrica. Recomiendo al lector que se desplace hacia la respuesta de @Marek Gregor (y la votó a favor ...)
Stav

Respuestas:


307

A partir de Java8 es posible usarlo String.join().

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

Genera:

Hello, World, !

De lo contrario, Apache Commons Lang tiene una StringUtilsclase que tiene una joinfunción que unirá matrices para crear un String.

Por ejemplo:

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

Genera lo siguiente String:

Hello, World, !

77
Para el beneficio de las personas que buscan esta respuesta, probablemente debería tenerse en cuenta que esto también es el equivalente de una unión Perl.
k-den

3
dice que no está definido para mí
Ninjaxor

@Ninjaxor 1. commons-lang * jar debe estar en classpath 2. import org.apache.commons.lang3.StringUtils;
peterh - Restablece a Mónica el

9
Le recomendaría que edite esta respuesta para agregar una referencia al nuevo String.join()método introducido en Java 8. De esta manera, el gran número de personas que leen esta respuesta aceptada se beneficiarán de ese conocimiento. Actualmente, la respuesta más votada que menciona este hecho se pierde bastante abajo ...
Duncan Jones

1
Vale la pena mencionar que String.join()funcionaría solo para List<CharSequence>o CharSequence[]elementos.
Enigo

71

Si estabas buscando qué usar en Android, es:

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

por ejemplo:

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

2
Esta es claramente la mejor respuesta para todas las versiones de Android, ya que Java 8 solo se lanzará en Android en un momento. Esta solución utiliza las bibliotecas de Android integradas, en lugar de estas soluciones tontas de "incluir una gran biblioteca para realizar una acción".
LukeStoneHm

Es septiembre de 2017, Java 8 para Android todavía está muy lejos. Gracias por esta respuesta!
Aenadon


53

Podría escribir fácilmente una función de este tipo en aproximadamente diez líneas de código:

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
Buena práctica según usted ... no existe un estándar universal para tales cosas.
phoebus

24
Pero si incluyera llaves, eso habría agregado dos líneas más de código, ¡y no podría haber afirmado haberlo hecho en 11 líneas!
Jay

8
el problema es cuando después de un tiempo, o alguien más, tiene prisa, agrega otra línea a eso si / para sin agregar llaves; o eliminar return null después de if (k == 0), que en algunos casos se compilaría pero será incorrecto. Entonces es mejor sacrificar una línea extra por esa llave de cierre (la abertura puede permanecer en la misma línea si / por).
Milán

16
Creo que es increíble que, si bien la mayoría de los idiomas incorporan dicha funcionalidad en su núcleo, la comunidad Java alienta a todos a reinventar la rueda.
John Strickler

33
11 líneas? ¡Bah! ¡Puedo hacerlo en 1! Simplemente elimine todos los caracteres de nueva línea en el archivo fuente.
Thomas Eding

25

Un pequeño mod en lugar de usar 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();
}

Votado porque no necesita agregar ninguna biblioteca.
givanse

10
Línea 7: ¿Es mejor si se usa .append()dos veces para cada uno en Stringlugar de concatenarlos y luego agregarlos al generador?
Talha Ahmed Khan

18

Como con muchas preguntas últimamente, Java 8 al rescate:


Java 8 agregó un nuevo método estático al java.lang.Stringque hace exactamente lo que quieres:

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

Utilizándolo:

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

Resultados en:

"Hello, World, !"

14

La biblioteca de guayaba de Google también tiene este tipo de capacidad . Puede ver el ejemplo de Cadena [] también desde la API.

Como ya se describió en la api, tenga cuidado con la inmutabilidad de los métodos de construcción.

Puede aceptar una variedad de objetos para que funcione en su caso. En mi experiencia anterior, intenté unirme a una pila que es iterable y funciona bien.

Muestra de mí:

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

imprime: |i am a coder|


9

Dado:

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

Luego, como alternativa a la respuesta de Coobird, donde el pegamento es ",":

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

O para concatenar con una cadena diferente, como "& amp;".

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

Sin embargo ... este SOLO funciona si sabe que los valores en la matriz o lista NO contienen la cadena de caracteres ",".


Arrays.asList(a).toString()trabajó para lo que quería hacer
Solomon Ucko

9

Si está utilizando Spring Framework, entonces tiene la clase StringUtils :

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

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

8

No en el núcleo, no. Sin embargo, la búsqueda de "java array join string glue" le dará algunos fragmentos de código sobre cómo lograr esto.

p.ej

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
Utilice StringBuilder (no apto para subprocesos) en lugar de StringBuffer (seguro para subprocesos) para un mejor rendimiento. La interfaz es la misma.
Asaph

2
Esto parece ser de snippets.dzone.com/posts/show/91 . Los comentarios sugieren una versión muy mejorada: unión de cadena estática pública (Iterable <? Extend Object> pColl, String separator) {Iterator <? extiende Object> oIter; if (pColl == null || (! (oIter = pColl.iterator ()) .hasNext ())) return ""; StringBuilder oBuilder = new StringBuilder (String.valueOf (oIter.next ())); while (oIter.hasNext ()) oBuilder.append (separador) .append (oIter.next ()); return oBuilder.toString (); }
Quantum7

6

Si aterrizó aquí buscando una conversión rápida de matriz a cadena, pruebe Arrays.toString () .

Crea una representación de cadena del Object[]pasado. El resultado está rodeado de corchetes ( "[]"), cada elemento se convierte en una Cadena a través de String.valueOf(Object)y se separa por ", ". Si la matriz es null, entonces "null"se devuelve.


¡MUCHAS GRACIAS! Las cadenas están separadas por "," y todo tiene "[]" alrededor, lo cual está bien para mí.
John Henckel

5

Solo por el "Tengo el más corto" desafío , aquí hay minas;)

Iterativo:

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

Recursivo:

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
La versión recursiva es elegante. Definitivamente voy a usar eso.
Pete

La versión recursiva puede ser elegante, pero ineficiente para grandes matrices (" copyOfRange()").
Ogre Psalm33


4

Así es como lo hago.

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

Una alternativa similar

/**
 * @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

Mi giro

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

¿Te gusta mi forma de 3 líneas usando solo los métodos de la clase 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
No está destinado a ser eficiente. Úselo StringBuildersi necesita eficiencia: P
Ryoichiro Oka

0

Para obtener "str1, str2" de "str1", "str2", "":

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

También puede agregar cheque nulo adicional


0

En caso de que esté usando la biblioteca funcional de Java y por alguna razón no pueda usar Streams de Java 8 (que podría ser el caso al usar el complemento Android + Retrolambda), aquí hay una solución funcional para usted:

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

Tenga en cuenta que no es el enfoque más eficiente, pero funciona bien para listas pequeñas.


-1

Lo hago de esta manera usando un 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(concatenación de cadenas con el operador más) anula el propósito de usar a StringBuilder.
quietmint

Además, este enfoque significaría que una matriz como: {"foo", "bar"} con delimitador ":" se convertiría en "foo: bar:"
pioto

-2

Hay una técnica simple de taquigrafía que uso la mayoría de las veces.

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

Esto solo funciona con delimitadores de longitud 1 y requiere 'números mágicos' (aunque bastante locales) si desea un delimitador de una longitud diferente.
maiwald

Puedes agregar varios personajes mientras
agregas

que simplemente hacer: op = op.substring (0, op.length () - ",". length ()); ¿Cual es el problema?
Dennis

-3

java.util.Arrays tiene un método 'asList'. Junto con la API java.util.List / ArrayList, esto le brinda todo lo que necesita :;

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

77
La pregunta es cómo unir un conjunto de cadenas con un delimitador, no cómo unir dos conjuntos de cadenas.
toolbear
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.