Java: função para matrizes como o join () do PHP?


Respostas:


307

A partir do Java8 , é possível usar String.join().

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

Gera:

Hello, World, !

Caso contrário, o Apache Commons Lang tem uma StringUtilsclasse que possui uma joinfunção que unirá matrizes para criar a String.

Por exemplo:

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

Gera o seguinte String:

Hello, World, !

7
Para o benefício das pessoas que buscam essa resposta, provavelmente deve-se notar que isso também é o equivalente a uma associação ao Perl.
den-k

3
ele diz que está indefinido para mim
Ninjaxor

@Ninjaxor 1. commons-lang * jar deve estar no caminho de classe 2. import org.apache.commons.lang3.StringUtils;
peterh - Restabelece Monica

9
Eu recomendo que você edite esta resposta para anexar uma referência ao novo String.join()método introduzido no Java 8. Dessa forma, o grande número de pessoas que lêem essa resposta aceita se beneficiará desse conhecimento. Atualmente, o mais votado resposta mencionar este fato é bastante perdido abaixo ...
Duncan Jones

1
Vale ressaltar que String.join()funcionaria apenas para List<CharSequence>ou CharSequence[]elementos.
Enigo

71

Se você estava procurando o que usar no Android, é:

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

por exemplo:

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

2
Essa é claramente a melhor resposta para todas as versões do Android, já que o Java 8 só será lançado no Android daqui a pouco. Esta solução usa as bibliotecas Android integradas, em vez dessas soluções tolas "incluem uma enorme biblioteca para executar uma ação".
LukeStoneHm

Em setembro de 2017, o Java 8 para Android ainda está longe. Obrigado por esta resposta!
Aenadon


53

Você poderia escrever facilmente essa função em cerca de dez linhas 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
Boas práticas para você ... não existe um padrão universal para essas coisas.
Phoebus 04/10/09

24
Mas se eu incluísse chaves, isso acrescentaria mais duas linhas de código, e eu não poderia ter afirmado ter feito isso em 11 linhas!
Jay

8
o problema é quando você, depois de um tempo, ou outra pessoa, com pressa, adiciona outra linha àquela se / para sem adicionar chaves; ou delete return null depois de if (k == 0), que em alguns casos seria compilado, mas estará incorreto. Então é melhor sacrificar uma linha extra para essa chave de fechamento (a abertura pode permanecer na mesma se / para a linha).
milan

16
Eu acho incrível que, embora a maioria das linguagens inclua essa funcionalidade em seu núcleo, a comunidade Java incentive todos a reinventar a roda.
John Strickler

33
11 linhas? Bah! Eu posso fazer isso em 1! Simplesmente remova todos os caracteres de nova linha no arquivo de origem.
Thomas Eding

25

Um pequeno mod em vez 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();
}

Votou porque você não precisa adicionar nenhuma biblioteca.
givanse

10
Linha 7: É melhor usar .append()duas vezes para cada um em Stringvez de concatená-las e depois anexá-las ao construtor.
precisa

18

Como com muitas perguntas recentemente, o Java 8 para o resgate:


O Java 8 adicionou um novo método estático ao java.lang.Stringqual faz exatamente o que você deseja:

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

Usando isso:

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

Resulta em:

"Hello, World, !"

14

A biblioteca do Google goiaba também possui esse tipo de capacidade . Você pode ver o exemplo String [] também na API.

Como já descrito na API, tenha cuidado com a imutabilidade dos métodos do construtor.

Ele pode aceitar uma variedade de objetos para funcionar no seu caso. Na minha experiência anterior, tentei ingressar em um Stack que é iterável e funciona bem.

Amostra de mim:

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

Então, como uma alternativa à resposta de coobird, onde a cola é ",":

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

Ou para concatenar com uma sequência diferente, como "& amp;".

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

No entanto ... este funciona SOMENTE se você souber que os valores na matriz ou na lista NÃO contêm a cadeia de caracteres ",".


Arrays.asList(a).toString()trabalhou para o que eu queria fazer
Solomon Ucko

9

Se você estiver usando o Spring Framework , terá a classe StringUtils :

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

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

8

Não no núcleo, não. Uma pesquisa por "cola de cadeia de junção de matriz java" fornecerá alguns trechos de código sobre como conseguir isso.

por exemplo

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
Use StringBuilder (não seguro para threads) no lugar de StringBuffer (seguro para threads) para obter melhor desempenho. A interface é a mesma.
Asaph

2
Parece ser de snippets.dzone.com/posts/show/91 . Os comentários sugerem uma versão muito melhorada: junção estática pública de String (Iterável <? Estende Objeto> pColl, separador de String) {Iterador <? estende Object> oIter; if (pColl == null || (! (oIter = pColl.iterator ()) .hasNext ())) return ""; StringBuilder oBuilder = novo StringBuilder (String.valueOf (oIter.next ())); while (oIter.hasNext ()) oBuilder.append (separador) .append (oIter.next ()); retornar oBuilder.toString (); }
Quantum7 17/03/10

6

Se você chegou aqui procurando uma conversão rápida de matriz para string, tente Arrays.toString () .

Cria uma representação String do Object[]passado. O resultado é cercado por colchetes ( "[]"), cada elemento é convertido em uma String por meio de String.valueOf(Object)e separado por ", ". Se a matriz for null, então "null"será retornado.


MUITO OBRIGADO! As strings são separadas por "," e a coisa toda tem "[]" ao redor, o que é bom para mim.
John Henckel

5

Apenas para o desafio "Eu tenho o menor" , aqui estão as 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
A versão recursiva é elegante. Definitivamente vou usar isso.
Pete

A versão recursiva pode ser elegante, mas ineficiente para matrizes grandes (" copyOfRange()").
Ogre Psalm33


4

É assim que eu faço.

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

Uma alternativa semelhante

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

Minha rotação.

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

Você gosta do meu caminho de 3 linhas usando apenas os métodos da classe 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
Não é para ser eficiente. Use StringBuilderse você precisar de eficiência: P
Ryoichiro Oka

0

Para obter "str1, str2" de "str1", "str2", "":

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

Além disso, você pode adicionar verificação nula extra


0

Caso você esteja usando a biblioteca Java Funcional e, por algum motivo, não possa usar o Streams do Java 8 (que pode ser o caso ao usar o plug-in Android + Retrolambda), aqui está uma solução funcional para você:

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

Observe que não é a abordagem mais eficiente, mas funciona bem para pequenas listas.


-1

Eu faço dessa maneira usando um 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(concatenação de cadeia de caracteres com o operador mais) anula todo o objetivo de usar a StringBuilder.
quietmint

Além disso, essa abordagem significaria que uma matriz como: {"foo", "bar"} com o delimitador ":" seria transformada em "foo: bar:"
pioto

-2

Existe uma técnica simples de taquigrafia que uso na maioria das vezes.

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

Isso funciona apenas com delimitadores de comprimento 1 e requer 'números mágicos' (embora bastante locais) se você quiser um delimitador de comprimento diferente.
Mai13

Você pode adicionar vários personagens enquanto anexando
Gaurav Adurkar

do que simplesmente: op = op.substring (0, op.length () - ",". length ()); qual é o grande problema?
Dennis

-3

java.util.Arrays possui um método 'asList'. Juntamente com a API java.util.List / ArrayList, você fornece tudo o que você precisa :;

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
A questão é como unir uma matriz de cadeias com um delimitador, não como unir duas matrizes de cadeias.
toolbear
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.