2

I have a list of strings in Java. I would like to to insert it into a string with commas, something like:

Input: [option1,option2,option3,option1,option4]
Output: option1,option2,option3,option4

I saw this topic and I really liked this one:

        StringBuilder result = new StringBuilder();
        String delimiter= "";
        for (String i : list) {
            result.append(delimiter).append(i);
            delimiter = ",";
        }
        return result.toString();

But what would be the best way to add support for unique only items? How can I return a string without any duplicates? I could remove duplication from list first but it feels like there is a better solution here.

WJS
  • 36,363
  • 4
  • 24
  • 39
abuka123
  • 441
  • 3
  • 12

3 Answers3

3

The best to avoid duplicates is to use a Set

  • TreeSet for alphabetical order

  • LinkedHashSet to keep insertion order (initial order)

StringBuilder result = new StringBuilder();
String delimiter= "";
for (String i : new LinkedHashSet<String>(list)) {
    result.append(delimiter).append(i);
    delimiter = ",";
}
return result.toString();

But you can just do String.join(',', new LinkedHashSet<String>(list))


Back to List

List<String> inputList = (unique) ? new ArrayList<>(new HashSet<>(list)) : list;

Case-insensitive

Set<String> check = new HashSet<String>();
StringBuilder result = new StringBuilder();
String delimiter= "";
for (String i : list) {
    if(!check.contains(i.toLowerCase())){
        result.append(delimiter).append(i);
        delimiter = ",";
        check.add(i.toLowerCase());
    }
}
return result.toString();
azro
  • 53,056
  • 7
  • 34
  • 70
  • Reordering the values is probably not appropriate. – Andreas Jun 01 '20 at 17:24
  • Using `HashSet` will sort alphabetically the values? – abuka123 Jun 01 '20 at 17:27
  • Also, I'm trying to add support to a flag. I would use something like `List inputList = (unique) ? new HashSet(list) : list;` But it looks like I can't convert `HashSet` to `List`. Is there a way to easily support the `unique` flag? – abuka123 Jun 01 '20 at 17:28
  • Using `LinkedHashSet` would retain original order (without using "external set"). Using `TreeSet` would order the values alphabetically. – Andreas Jun 01 '20 at 17:29
  • @abuka123 `Collection inputList = (unique ? new LinkedHashSet<>(list) : list);` --- No need to copy the values twice to get a `List`. The `for` loop works for Collections. It actually works for anything `Iterable`. – Andreas Jun 01 '20 at 17:30
  • @abuka123 if you want back to list read the end of my answer, if you jsut want a Collection (no matter list or set) look ANdreas comment – azro Jun 01 '20 at 17:31
  • Another question if you allow. Is there a way to handle case sensitive, meaning `Hi = hi` or does it making it much harder? – abuka123 Jun 01 '20 at 17:43
  • @abuka123 you need an external Set, as I just show in y post at the end – azro Jun 01 '20 at 17:45
0

You can stream() the list and collect only distinct values. Afterwards, you can just String.join(...) them to a comma separated String, like this:

public static void main(String[] args) {
    // example values
    List<String> list = new ArrayList<>();
    list.add("option1");
    list.add("option2");
    list.add("option3");
    list.add("option4");
    list.add("option1");
    list.add("option3");
    list.add("option5");

    // stream the list and collect only distinct values in a new list
    List<String> distinctOptions = list.stream()
                                        .distinct()
                                        .collect(Collectors.toList());
    // then create a comma separated String from that list
    String commaSeparatedUniqueStrings = String.join(",", distinctOptions);
    // and print it
    System.out.println(commaSeparatedUniqueStrings);
}

The output is

option1,option2,option3,option4,option5
deHaar
  • 17,687
  • 10
  • 38
  • 51
  • Why build a list? Why not just use the stream to build the desired result string? See [my comment](https://stackoverflow.com/questions/62137512/convert-a-list-of-string-into-a-comma-separated-string-without-duplications#comment109897191_62137512). – Andreas Jun 01 '20 at 17:34
  • @Andreas this is just an example and may of course be optimized... Sure, there's no real need for an intermediate list, but it makes the example more readable and easier to understand. But it is not optimal, I admit. – deHaar Jun 01 '20 at 17:49
0

Extra requirements from comments:

Sorted

If sorting the values is ok, handling case-sensitive is easiest done using a TreeSet with a case-insensitive Comparator, like the String.CASE_INSENSITIVE_ORDER, or by using a Collator for full language support.

static String toString(List<String> list, boolean unique) {
    Collection<String> dataToProcess = list;
    if (unique) {
        dataToProcess = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        dataToProcess.addAll(list);
    }
    
    StringBuilder result = new StringBuilder();
    String delimiter= "";
    for (String s : dataToProcess) {
        result.append(delimiter).append(s);
        delimiter = ",";
    }
    return result.toString();
}

Test

List<String> list = Arrays.asList("option1", "option3", "OPTION1", "OPTION2", "option4", "option2");
System.out.println(toString(list, false));
System.out.println(toString(list, true));

Output

option1,option3,OPTION1,OPTION2,option4,option2
option1,OPTION2,option3,option4

Notice how the "unique" result is sorted, but the non-unique result is not.

Using Collator

For better language support, use a Collator:

    if (unique) {
        Collator collator = Collator.getInstance(/*Locale.GERMANY*/);
        collator.setStrength(Collator.SECONDARY);
        dataToProcess = new TreeSet<>(collator);
        dataToProcess.addAll(list);
    }

Unsorted

To do it without sorting the values, we'll keep using the TreeSet but build a new list.

    if (unique) {
        Collator collator = Collator.getInstance(/*Locale.GERMANY*/);
        collator.setStrength(Collator.SECONDARY);
        Set<String> set = new TreeSet<>(collator);
        dataToProcess = new ArrayList<>();
        for (String s : list)
            if (set.add(s))
                dataToProcess.add(s);
    }

Output

option1,option3,OPTION1,OPTION2,option4,option2
option1,option3,OPTION2,option4
Community
  • 1
  • 1
Andreas
  • 154,647
  • 11
  • 152
  • 247