3

I have List<String> list = Arrays.asList("A", "B", "C");
I want to join all string inside list with delimiter , in reverse order :

//result
String joinedString = "C,B,A";

what is the best approach to achieve this?
currently I use index loop :

String joinedString = "";
List<String> list = Arrays.asList("A", "B", "C");
for (int i = list.size() - 1; i >= 0; i--) {
     String string = list.get(i);
     joinedString = joinedString + string + ",";
}
//to remove ',' from the last string
if(joinedString.length() > 0) {
    joinedString = joinedString.substring(0, joinedString.length() - 1);
}

//Output    
C,B,A
m fauzan abdi
  • 436
  • 5
  • 12
  • If it works, it's generally good enough. – RaminS Jan 26 '19 at 02:07
  • is it? but could I achieve it better without using index loop? – m fauzan abdi Jan 26 '19 at 02:11
  • 1
    You might find [How to get a reversed list view on a list in Java?](https://stackoverflow.com/questions/3962766/how-to-get-a-reversed-list-view-on-a-list-in-java) useful if you don't want to modify the original list. – Kevin Ji Jan 26 '19 at 03:33

7 Answers7

5

If you don't want to modify the list by calling Collections.reverse(List<?> list) on it, iterate the list in reverse.

If you don't know the list type, use a ListIterator to iterate the list backwards without loss of performance, e.g. an normal i = 0; i < size() loop over a LinkedList would otherwise perform badly.

To join the values separated by commas, use a StringJoiner (Java 8+).

List<String> list = Arrays.asList("A", "B", "C");

StringJoiner joiner = new StringJoiner(",");
for (ListIterator<String> iter = list.listIterator(list.size()); iter.hasPrevious(); )
    joiner.add(iter.previous());
String result = joiner.toString();

System.out.println(result); // print: C,B,A
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • https://stackoverflow.com/questions/322715/when-to-use-linkedlist-over-arraylist-in-java/40375897 – Ravindra Ranwala Jan 26 '19 at 14:46
  • the same IDEA using streams: `String result= Stream.iterate(list.listIterator(list.size()), it -> it) /*.takeWhile(ListIterator::hasPrevious) // java 9+ */ .limit(list.size()) /*java 8 workaround*/ .map(ListIterator::previous) .collect(Collectors.joining(","));` – Andrey Lavrukhin Aug 08 '20 at 14:58
  • 1
    @AndreyLavrukhin That is extremely bad stream logic, because you're violating the contract of [`map()`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#map-java.util.function.Function-) when you call [`previous()`](https://docs.oracle.com/javase/8/docs/api/java/util/ListIterator.html#previous--), because it is not a *stateless* function. To do it correctly, see [**How to convert an iterator to a stream?**](https://stackoverflow.com/q/24511052/5221149) – Andreas Aug 08 '20 at 17:21
3

The simplest is to use Collections#reverse and String#join.

List<String> list = Arrays.asList("A", "B", "C");
Collections.reverse(list);
String joinedString = String.join(",", list);
RaminS
  • 2,208
  • 4
  • 22
  • 30
  • 1
    Good thing OP used `Arrays.asList(...)` and not `List.of(...)`, since this solution wouldn't work otherwise. – Andreas Jan 26 '19 at 02:33
  • Can't find `List.of` by Googling. Got a link to documentation? @Andreas – RaminS Jan 26 '19 at 02:38
  • Added in Java 9: [`List.of(E...)`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html#of(E...)) --- Or this link to see [all the overloads](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html#i15). – Andreas Jan 26 '19 at 02:38
2

Here's one solution using Java 8:

Collections.reverse(list);

//res contains the desired string
String res = list.stream().collect(Collectors.joining(","));
Prashant Pandey
  • 4,332
  • 3
  • 26
  • 44
1

Using a Supplier

List<String> list = Arrays.asList("A", "B", "C");
int i[] = { list.size() };
Supplier<String> supplier = () -> (i[0] > 0) ? list.get(--i[0]) : null;
String s, reverse = "";
while ((s = supplier.get()) != null) {
        reverse +=","+s;
}
reverse = (reverse.length() > 0) ? reverse = reverse.substring(1): "" ;

or insted of while loop

reverse = list.stream().map(l->supplier.get()).collect(Collectors.joining(","));
Traian GEICU
  • 1,750
  • 3
  • 14
  • 26
1

It may be usefull joining-like collector:

    public static Collector<CharSequence, ?, String> joiningReversed(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {
    return Collector.of(StringBuilder::new,
            (sb, item) -> {
                if (sb.length() != 0) {
                    sb.insert(0, delimiter);
                }
                sb.insert(0, item);
            },
            (a, b) -> {
                throw new UnsupportedOperationException();
            },
            sb -> sb.insert(0, prefix).append(suffix).toString());
    }

and use it in streams:

    List<String> list = Arrays.asList("A", "B", "C");
    String result = list.stream()
                .collect(joiningReversed(",", "", ""));
    System.out.println(result);
0

Another way, using Comparator.

List<String> list = Arrays.asList("A", "B", "C");
list.sort(Comparator.reverseOrder());
String joinedString = String.join(",", list);
mogbee
  • 208
  • 2
  • 5
0

One method use StringBuilder

    StringBuilder sb = new StringBuilder();
    List<String> strs = Arrays.asList("A", "b", "c","d");
    for (int i = 0; i < strs.size(); i++) {
        sb.append(strs.get(i));
        if (i != strs.size() - 1) {
            sb.append(",");
        }
    }
    System.out.println(sb.reverse().toString());
TongChen
  • 1,414
  • 1
  • 11
  • 21