Best way to build a delimited string from a list in java

怎甘沉沦 提交于 2019-12-13 16:04:03

问题


I have a list of objects, and each object has a string property. For example, I have a List<Person> and each Person has a firstName property. I want to build a comma-delimited, quoted string that looks like this:

'James', 'Lily', 'Michael'

Considering that java doesn't seem to have a join method (and besides, this is a bit more complicated than a simple delimited string), what's the most straightforward way to do this? I've been trying to code this for a bit but my code's gotten very messy and I could use some fresh input.


回答1:


If you want to do it simply and manually, you could do something like this:

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

Now mystr contains your list. Note that the comma is only added if we are not acting on the last element in the list (with index personlist.size() - 1).

Of course, there are more elegant/efficient methods to accomplish this, but this one is, in my opinion, the clearest.




回答2:


I used this for the same issue (Apache StringUtils)

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



回答3:


Just use the most straightforward way. Have a StringBuilder, loop over the List, surround each item with quotes, append it to builder and if there's more to come, append the comma.

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

Alternatively, you can also use the 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();

Note that using a StringBuilder is preferred over using += string concatenation since the latter implicitly creates a new string instance on the heap which might be performance and memory hogging when you've a lot of items.




回答4:


Jdk8 Lambda's solution:

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

This provides "," as the delimited, and a prefix and suffix of ".




回答5:


Here is unit test with expectations:

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\'"));
    }

}

Converter is just an interface:

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

And finally Joiner:

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

By using different converters it is easy to join properties of different types.




回答6:


I like

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

The key advantage of this is that 90% of your execution time will probably be done in the inner while loop, and this solution only requires one comparison to determine if we need to exit the inner while loop.

Other solutions work too, but a solution that looks like:

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

embeds an unnecessary if statement within the while loop. This means an extra comparison will have to be made for each element, when the only differing element would be the last one.

By shifting the comparison for checking if the element is the last one to a comparison if there is more than one element, we only need to move the appended ", " to a prepended ", " for each element other than the first




回答7:


You can loop through each item in your List and use the StringBuilder.append() method to add each Name to the list. This aviods using the string class which will create a new instance of the string each time as string is immutable.

1) initialize your string builder 2) get the number of items in the list by using List.size()

int listSize = personList.size()

3) add the first opening paren and quote to your string

StringBuilderinstance.append("('")

4) use a for loop and add each name, ending quote, comma and opening quote to the stringBuilder instance, before calling the append method check to see if i equals listSize if you are at the last index only append the firstname, quote and closing paren:

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



回答8:


A simple solution implemented in core Java (no external dependencies) that doesn't make a conditional evaluation inside the loop might look like this:

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

Using StringBuffer avoids lots of String concatenation, which is ill-performant in Java.




回答9:


I would suggest you first add a method to your Person class:

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

Now you can use this:

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


来源:https://stackoverflow.com/questions/3426995/best-way-to-build-a-delimited-string-from-a-list-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!