2010-08-06 3 views
2

У меня есть список объектов, и каждый объект имеет свойство string. Например, у меня есть List<Person>, и каждый Person имеет свойство firstName. Я хочу построить через запятую, в кавычках строки, которая выглядит следующим образом:Лучший способ построить строку с разделителями из списка в java

'James', 'Lily', 'Michael' 

Учитывая то, что Java не кажется, есть способ присоединиться (и к тому же, это немного сложнее, чем просто строка с разделителями), что является самым простым способом сделать это? Я пытался закодировать это немного, но мой код стал очень грязным, и я мог использовать свежий ввод.

+0

Возможный дубликат [Java: convert List to join() d string] (http://stackoverflow.com/questions/1751844/java-convert-liststring-to-a-joind-string) – jjnguy

+0

или, http://stackoverflow.com/questions/1515437/java-function-for-arrays-like-phps-join – jjnguy

+1

Я не думаю, что это дубликат.Это не просто соединение с разделителем, я также хочу окружить каждый компонент кавычками. – froadie

ответ

2

Если вы хотите сделать это просто и вручную, вы могли бы сделать что-то вроде этого:

String mystr = ""; 
for(int i = 0; i < personlist.size(); i++) { 
    mystr += "\'" + personlist.get(i).firstName + "\'"; 
    if(i != (personlist.size() - 1)) { 
    mystr += ", "; 
    } 
} 

Теперь mystr содержит список. Обратите внимание, что запятая добавляется только в том случае, если мы не действуем на последний элемент в списке (с индексом personlist.size() - 1).

Конечно, есть более элегантные/эффективные методы для достижения этого, но этот, на мой взгляд, самый ясный.

+0

Выполнение множества конкатенации строк является злом в Java, и что условное внутри цикла будет означать много ненужных проверок. Эти комбинированные эффекты приносят плохую производительность для больших списков людей. – Tom

+0

Вы правы; однако контекст, по-видимому, способствует простоте работы. Но я согласен: это не подходящее решение для любого производственного приложения. Однако в целях обучения я думаю, что это начало. :) – hb2pencil

2

Просто используйте самый простой способ. У вас есть StringBuilder, петля над List, окружите каждый элемент кавычками, добавьте его в строитель, и если еще есть что добавить, добавьте запятую.

StringBuilder builder = new StringBuilder(); 
for (int i = 0; i < persons.size(); i++) { 
    builder.append("'").append(persons.get(i)).append("'"); 
    if (i < persons.size() - 1) { 
     builder.append(", "); 
    } 
} 
String string = builder.toString(); 

В качестве альтернативы, вы можете также использовать Iterator:

StringBuilder builder = new StringBuilder(); 
for (Iterator<Person> iter = persons.iterator(); iter.hasNext();) { 
    builder.append("'").append(iter.next()).append("'"); 
    if (iter.hasNext()) { 
     builder.append(", "); 
    } 
} 
String string = builder.toString(); 

Обратите внимание, что при использовании StringBuilder является предпочтительным по сравнению с использованием += конкатенации, поскольку последний неявно создает новый экземпляр строки в куче, которая может быть производительности и памяти, когда у вас много предметов.

0

Простое решение, реализованное в основных Java (без каких-либо внешних зависимостей), что не делает условную оценку внутри цикла может выглядеть следующим образом:

private static final char QUOTE = '\''; 
private static final String SEPARATOR = ", "; 

public static String join(List<Person> people) { 
    if (people.isEmpty()) { 
     return ""; 
    } 
    final StringBuilder builder = new StringBuilder(); 
    for (Person person : people) { 
     builder.append(QUOTE); 
     builder.append(person.getFirstName()); 
     builder.append(QUOTE); 
     builder.append(SEPARATOR); 
    } 
    builder.setLength(builder.length() - SEPARATOR.length()); 
    return builder.toString(); 
} 

Использование StringBuffer избегает много конкатенации строк, который болен -перформат в Java.

+0

Пожалуйста, кто бы ни проголосовал за это, оставляйте комментарий, чтобы я мог понять их возражение против этого решения? – Tom

+0

Изменение длины строителя в конце кажется мне взломанным. –

+0

Я не уверен, что согласен: setLength - полностью поддерживаемая функция StringBuilder, которая сама предназначена для облегчения локализованной мутации строк, и намерение здесь ясно. – Tom

0

Вы можете прокручивать каждый элемент в своем списке и использовать метод StringBuilder.append() для добавления каждого имени в список. Этот aviods использует строковый класс, который будет создавать новый экземпляр строки каждый раз, когда строка является неизменной.

1) инициализируйте построитель строк 2) получите количество элементов в списке, используя список.размер()

int listSize = personList.size() 

3) добавить первое открытие скобки и цитату в строку

StringBuilderinstance.append("('") 

4) использовать цикл и добавить каждое имя, окончание цитаты, запятой и открытие цитаты к StringBuilder Например, перед вызовом метода проверки Append, чтобы увидеть, если я равен listSize, если вы на последнем индексе только добавить в ПгвЬЫате, цитаты и закрытия скобка:

for(int i = 0, i<listSize, i++) 
{  
    if(i == listSize - 1) 
     StringBuilderinstance.append(firstName + "')") 
    else  
     StringBuilderinstance.append(firstName + "', '") 
} 
1

Мне нравится

if (list != null) { 
    Iterator iter = list.iter(); 
    if (iter.hasNext()) { 
    buffer.append(iter.next()); 
    while (iter.hasNext()) { 
     buffer.append(", "); 
     buffer.append(iter.next()); 
    } 
    } 
} 

Главное преимущество этого заключается в том, что 90% времени выполнения, вероятно, будет выполнено во внутреннем цикле while, и для этого решения требуется только одно сравнение, чтобы определить, нужно ли нам выйти из внутреннего цикла while.

Другие решения работают тоже, но это решение, которое выглядит следующим образом:

while (iter.hasNext()) { 
    buffer.append(iter.next()); 
    if (iter.hasNext()) { 
    buffer.append(", "); 
    } 
} 

встраивает ненужным, если оператор в то время цикла. Это означает, что для каждого элемента потребуется дополнительное сравнение, когда единственным отличительным элементом будет последний.

Перемещая сравнение для проверки того, является ли элемент последним для сравнения, если имеется более одного элемента, нам нужно только переместить добавленный «,» в добавочный «» для каждого элемента, отличного от первый

+1

+1. Второе решение было бы «if (iter.hasNext())», а не «if (! Iter.hasNext())». –

+0

@Sebastien, спасибо за комментарий. Должно быть, я ошибся ошибкой. Я вытащу его за других. –

0

Я хотел бы предложить вам первый добавить метод к вашему Person класс:

Person { 
    //... 
    String toListEntry() { 
     return "\'" + firstName + "\'"; 
    } 
} 

Теперь вы можете использовать это:

List<Person> list = //... get the list 
StringBuilder buf = new StringBuilder(list.get(0).toListEntry()); 

for(int i = 1; i < list.size(); i++) 
    buf.append(" , " + list.get(i).toListEntry()); 

String stringList = buf.toString(); 
1

Вот модульное тестирование ж Ith ожидания:

import static java.util.Arrays.*; 
import static org.hamcrest.CoreMatchers.*; 
import static org.junit.Assert.*; 
import org.junit.Test; 


public class JoinerTest { 

    private static final Converter<Person, String> PERSON_CONVERTER = 
     new Converter<Person, String>() { 
      @Override 
      public String convert(Person object) { 
       return object.getFirstName(); 
      } 
    }; 

    @Test 
    public void shouldPresentFirstNames() { 
     // given 
     Person person1 = new Person(); 
     person1.setFirstName("foo"); 
     Person person2 = new Person(); 
     person2.setFirstName("bar"); 
     Joiner<Person> joiner = new Joiner<Person>(", ", "\'"); 

     // when 
     String firstNames = joiner.join(PERSON_CONVERTER, 
         asList(person1, person2)); 

     // then 
     assertThat(firstNames, is("\'foo\', \'bar\'")); 
    } 

} 

конвертер является просто интерфейс:

public interface Converter<F, T> { 
    T convert(F object); 
} 

И, наконец, Столяр:

public class Joiner<T> { 

    private final String delimiter; 

    private final String quote; 

    public Joiner(String delimiter, String quote) { 
     this.delimiter = delimiter; 
     this.quote = quote; 
    } 

    public String join(Converter<T, String> converter, Iterable<T> objects) { 
     StringBuilder builder = new StringBuilder(); 
     for (T object : objects) { 
      String string = converter.convert(object); 
      builder.append(quote); 
      builder.append(string); 
      builder.append(quote); 
      builder.append(delimiter); 
     } 
     if (builder.length() > 0) { 
      builder.setLength(builder.length() - delimiter.length()); 
     } 
     return builder.toString(); 
    } 
} 

Используя различные преобразователи легко соединить свойства различных типов.

+0

Overengineering, на мой взгляд. –

+0

Я бы использовал guava [Joiner] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Joiner.html) сегодня – morisil

19

Я использовал это для того же выпуска (Apache StringUtils)

String joined = "'" + StringUtils.join(arrayOrList,"','") + "'"; 
+0

отличный ответ, bravooo :) –

2

раствор Jdk8 Lambda в:.

String quotedAndDelimited = Arrays.stream(values).collect(Collectors.joining("\",\"","\"","\"")); 

Это обеспечивает "" как с разделителями, а префикс и суффикс»

Смежные вопросы