2011-11-24 10 views
26

dado una listaunirse a una lista <String> en Java con comas y "y"

List<String> l = new ArrayList<String>(); 
l.add("one"); 
l.add("two"); 
l.add("three"); 

tengo un método

String join(List<String> messages) { 
     if (messages.isEmpty()) return ""; 
     if (messages.size() == 1) return messages.get(0); 
     String message = ""; 
     message = StringUtils.join(messages.subList(0, messages.size() -2), ", "); 
     message = message + (messages.size() > 2 ? ", " : "") + StringUtils.join(messages.subList(messages.size() -2, messages.size()), ", and "); 
     return message; 
    } 

que, por l, produce "una, dos y tres" . Mi pregunta es, ¿existe un método estándar (Apache-commons) que hace lo mismo ?, por ejemplo

WhatEverUtils.join(l, ", ", ", and "); 

Para aclarar. Mi problema no es conseguir que este método funcione. Funciona justo como yo quiero, está probado y todo está bien. Mi problema es que no pude encontrar algún módulo tipo Apache-commons que implemente tal funcionalidad. Lo cual me sorprende, ya que no puedo ser el primero en necesitar esto.

Pero entonces tal vez todos los demás sólo ha hecho

StringUtils.join(l, ", ").replaceAll(lastCommaRegex, ", and"); 
+0

No creo que haya una biblioteca de código abierto, pero aconsejo utilizar un paquete de recursos ya que no todos los idiomas usan la palabra en inglés "y". –

+0

@slipset, ¿por qué no utiliza alguna combinación de una biblioteca conocida y simplemente la modifica un poco? Tenga en cuenta que "y" es una palabra en inglés, por lo que si existiera dicha biblioteca, tenía que tener soporte para varios idiomas – smas

+0

Podría no haber sido claro, pero he escrito el método que muestro en mi pregunta y funciona como yo quiero. – slipset

Respuesta

13

me gusta el uso de colecciones de Google para este propósito. Limpio y muy útil:

Joiner.on(",").join(myList) 

Este tipo de código se ha escrito de nuevo el tiempo y el tiempo y lugar que debe ser liberado a la implementación de la lógica de aplicación específica.

Si utiliza Maven, adjunto la dependencia:

<dependency> 
    <groupId>com.google.collections</groupId> 
    <artifactId>google-collections</artifactId> 
    <version>1.0</version> 
</dependency> 

Se ha un montón de otras características fresco maravilloso también!

EDITAR: Para completar, esto generará la lista "uno, dos y tres".

List<String> originalList = Arrays.asList("one", "two", "three"); 
Joiner.on(", ").join(originalList.subList(0, originalList.size() - 1)) 
    .concat(", and ").concat(originalList.get(originalList.size() - 1)); 
+2

Solo para su información: google collections ha quedado en desuso en favor de Guava (http://code.google.com/p/guava-libraries/), que es un superconjunto completamente compatible con versiones anteriores. –

+0

Muy correcto ... Me olvidé de eso. La dependencia Maven si alguien está interesado: com.google.guava guayaba 10.0.1

+1

no veo por qué estás downvoting respuestas con unirse método que producen: "uno , dos tres". ¿Es tan difícil reemplazar la última coma por cualquier cadena que quieras, o algo similar? Esta es una respuesta 100% correcta que da a @slipset una dirección posible que puede resolver su problema. – smas

1

No conozco ningún carpintero Apache Cadena que puede apoyar la adición de and en la cadena unido.

Aquí hay un código no probado que va a hacer lo que pidió:

public static String join(String separator, List<String> mList, boolean includeAndInText) { 
    StringBuilder sb = new StringBuilder(); 
    int count = 0; 

    for (String m: mList) { 
     if (includeAndInText && (count + 1 != mList.size())) { 
      sb.append (" and "); 
     } 

     sb.append(m); 
     count++; 
     if (count < mList.size()) { 
      sp.append(separator); 
     }  
    } 

    return sb.toString(); 
} 
+0

lo siento, pero no creo que este sea el mejor enfoque para este problema. IMO deberíamos usar algo que existe (por ejemplo, unirnos a Apache) y modificarlo un poco para obtener "y", "o" o algo que esperamos tener. – smas

+0

@smas, vale, no estoy de acuerdo. Cambiar una biblioteca existente para que cumpla con su requisito de ** solo ** no es una opción obvia, ya que (y no lo creo) usted enviará su cambio a Apache. Además, si se lanza otra versión de 'StringUtils', deberá mantenerla y asegurarse de que su cambio no se vea afectado (eliminado).Digo, deje la implementación de la biblioteca AS-IS y escriba su propia clase de utilidad. –

+1

I diagree también. En el mundo de los negocios, bibliotecas muy conocidas como StringUtils se usan muy a menudo para evitar reinventar la rueda. Si conoce algunos cambios, escribe pruebas unitarias. Para este caso, únase a la escritura solo porque "y" debe haber una pérdida de tiempo, dinero y estilo de Programación Orientada a Objetos. – smas

11

¿Qué hay de join de: org.apache.commons.lang.StringUtils

Ejemplo:

StringUtils.join(new String[] { "one", "two", "three" }, ", "); // one, two, three 

tener "y" o", y "puedes simplemente reemplazar la última coma".

+0

Eso no produce '" uno, dos y tres "' como solicitó el OP. Observe: Está usando ese método 'join' en su pregunta –

+0

@Lukas, pero puede reemplazar la última coma, ¿no? No veo sentido tener una biblioteca que me agregue este "y" en el método de unión. – smas

+0

FYI - He planteado https://issues.apache.org/jira/browse/LANG-1037 para solicitar la inclusión de métodos adicionales para hacer esto. Intentaré implementarlo en la próxima versión. –

3

Otras respuestas hablan de "reemplazar la última coma", que no es seguro en caso de que el último término contenga una coma.

En lugar de utilizar una biblioteca, que sólo puede utilizar una línea (aunque largo) de código de JDK:

public static String join(List<String> msgs) { 
    return msgs == null || msgs.size() == 0 ? "" : msgs.size() == 1 ? msgs.get(0) : msgs.subList(0, msgs.size() - 1).toString().replaceAll("^.|.$", "") + " and " + msgs.get(msgs.size() - 1); 
} 

Ver un live demo de este manejo de todos los casos extremos código.


FYI, he aquí una más legible dos forro:

public static String join(List<String> msgs) { 
    int size = msgs == null ? 0 : msgs.size(); 
    return size == 0 ? "" : size == 1 ? msgs.get(0) : msgs.subList(0, --size).toString().replaceAll("^.|.$", "") + " and " + msgs.get(size); 
} 
7

Con Java 8, puede utilizar corrientes con carpinteros.

Collection<String> strings; 
... 
String commaDelimited = strings.stream().collect(Collectors.joining(",")); 
// use strings.parallelStream() instead, if you think 
// there are gains to be had by doing fork/join 
21

En Java 8 se puede utilizar String.join() como siguiente:

Collection<String> elements = ....; 
String result = String.join(", ", elements); 
0

para producir una salida gramatical en Inglés hay 3 casos a considerar al concatenar una lista de cadenas:

  1. "A"

  2. "A and B"

  3. "A, B, y C.

Esto se puede lograr usando Java estándar o de guayaba como a continuación. Las soluciones son básicamente las mismas y solo depende de la preferencia que desee usar.

import com.google.common.base.Joiner; 
import com.google.common.collect.ImmutableList; 

import org.junit.Test; 

import java.util.List; 

import static org.junit.Assert.assertEquals; 

public class JoinListTest { 

    @Test 
    public void test_join() { 
     // create cases (don't need to use ImmutableList builder from guava) 
     final List<String> case1 = new ImmutableList.Builder<String>().add("A").build(); 
     final List<String> case2 = new ImmutableList.Builder<String>().add("A", "B").build(); 
     final List<String> case3 = new ImmutableList.Builder<String>().add("A", "B", "C").build(); 
     // test with standard java 
     assertEquals("A", joinListGrammaticallyWithJava(case1)); 
     assertEquals("A and B", joinListGrammaticallyWithJava(case2)); 
     assertEquals("A, B, and C", joinListGrammaticallyWithJava(case3)); 
     // test with guava 
     assertEquals("A", joinListGrammaticallyWithGuava(case1)); 
     assertEquals("A and B", joinListGrammaticallyWithGuava(case2)); 
     assertEquals("A, B, and C", joinListGrammaticallyWithGuava(case3)); 
    } 

    private String joinListGrammaticallyWithJava(final List<String> list) { 
     return list.size() > 1 
       ? String.join(", ", list.subList(0, list.size() - 1)) 
        .concat(String.format("%s and ", list.size() > 2 ? "," : "")) 
        .concat(list.get(list.size() - 1)) 
       : list.get(0); 
    } 

    private String joinListGrammaticallyWithGuava(final List<String> list) { 
     return list.size() > 1 
       ? Joiner.on(", ").join(list.subList(0, list.size() - 1)) 
        .concat(String.format("%s and ", list.size() > 2 ? "," : "")) 
        .concat(list.get(list.size() - 1)) 
       : list.get(0); 
    } 

} 
Cuestiones relacionadas