Java: соединение строки из списка‹String› в обратном порядке

У меня есть List<String> list = Arrays.asList("A", "B", "C");
Я хочу соединить всю строку внутри списка с разделителем , в обратном порядке:

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

каков наилучший подход для достижения этого?
в настоящее время я использую индексный цикл:

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

person m fauzan abdi    schedule 26.01.2019    source источник
comment
Если это работает, это в целом достаточно хорошо.   -  person RaminS    schedule 26.01.2019
comment
это? но могу ли я добиться этого лучше, не используя индексный цикл?   -  person m fauzan abdi    schedule 26.01.2019
comment
Вы можете найти Как получить обратный представление списка в списке в Java? полезно, если вы не хотите изменять исходный список.   -  person kevinji    schedule 26.01.2019


Ответы (7)


Если вы не хотите изменять список, вызвав Collections.reverse(List<?> list) на нем перебрать список в обратном порядке.

Если вы не знаете тип списка, используйте ListIterator для итерации списка в обратном направлении без потери производительности, например обычный цикл i = 0; i < size() поверх LinkedList в противном случае работал бы плохо.

Чтобы объединить значения, разделенные запятыми, используйте StringJoiner (Ява 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
person Andreas    schedule 26.01.2019
comment
stackoverflow. ком/вопросы/322715/ - person Ravindra Ranwala; 26.01.2019
comment
та же ИДЕЯ с использованием потоков: 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(",")); - person Andrey Lavrukhin; 08.08.2020
comment
@AndreyLavrukhin Это чрезвычайно плохая логика потока, потому что вы нарушаете контракт map() при вызове previous(), потому что это не функция без сохранения состояния. Чтобы сделать это правильно, см. Как преобразовать итератор в поток? - person Andreas; 08.08.2020

Самый простой способ — использовать Collections#reverse и String#join.

List<String> list = Arrays.asList("A", "B", "C");
Collections.reverse(list);
String joinedString = String.join(",", list);
person RaminS    schedule 26.01.2019
comment
Хорошо, что OP использовал Arrays.asList(...), а не List.of(...), иначе это решение не сработало бы. - person Andreas; 26.01.2019
comment
Не удается найти List.of с помощью Google. Есть ссылка на документацию? @Андреас - person RaminS; 26.01.2019
comment
Добавлено в Java 9: ​​List.of(E...) --- Или эта ссылка для просмотра все перегрузки. - person Andreas; 26.01.2019

Использование поставщика

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): "" ;

или вместо цикла while

reverse = list.stream().map(l->supplier.get()).collect(Collectors.joining(","));
person Traian GEICU    schedule 26.01.2019

Вот одно решение с использованием Java 8:

Collections.reverse(list);

//res contains the desired string
String res = list.stream().collect(Collectors.joining(","));
person Prashant Pandey    schedule 26.01.2019

Может быть полезным сборщик, похожий на соединение:

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

и использовать его в потоках:

    List<String> list = Arrays.asList("A", "B", "C");
    String result = list.stream()
                .collect(joiningReversed(",", "", ""));
    System.out.println(result);
person Andrey Lavrukhin    schedule 12.07.2020
comment
Примечание: это работает для любого последовательного потока, даже неопределенной длины. - person Andrey Lavrukhin; 08.08.2020

Другой способ, используя Comparator.

List<String> list = Arrays.asList("A", "B", "C");
list.sort(Comparator.reverseOrder());
String joinedString = String.join(",", list);
person mogbee    schedule 26.01.2019
comment
OP не хочет, чтобы значение отсортировано, просто было обратным текущему порядку. Тот факт, что показанный пример имеет значения в порядке возрастания, является произвольным. - person Andreas; 26.01.2019
comment
это перебор. достаточно обратить его вспять - person Witold Kaczurba; 26.01.2019

Один метод использует 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());
person TongChen    schedule 26.01.2019