Как добавить символ новой строки для всех строк, кроме последнего?

Я более подробно повторяю HashMap (см. мой более ранний вопрос) и строю строку, состоящую из данных, содержащихся на Карте. Для каждого элемента у меня будет новая строка, но для самого последнего элемента мне не нужна новая строка. Как я могу это достичь? Я думал, что могу сделать какой-то чек, чтобы увидеть, является ли запись последней или нет, но я не уверен, как это сделать.

Спасибо!

Ответ 1

Измените свой мыслительный процесс с "добавьте прерывание строки все, кроме последнего раза", чтобы "довести разрыв строки до первого раза":

boolean first = true;
StringBuilder builder = new StringBuilder();

for (Map.Entry<MyClass.Key,String> entry : data.entrySet()) {
    if (first) {
        first = false;
    } else {
        builder.append("\n"); // Or whatever break you want
    }
    builder.append(entry.key())
           .append(": ")
           .append(entry.value());
}

Ответ 2

один метод (с извинениями за Джона Скита за заимствование части его кода Java):

StringBuilder result = new StringBuilder();

string newline = "";  
for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    result.append(newline)
       .append(entry.key())
       .append(": ")
       .append(entry.value());

    newline = "\n";
}

Ответ 3

Как насчет этого?

StringBuilder result = new StringBuilder();

for(Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    builder.append(entry.key())
       .append(": ")
       .append(entry.value())
       .append("\n");
}

return builder.substring(0, builder.length()-1);

Обязательные извинения и благодарность Джону и Джоулу за "заимствование" из их примеров.

Ответ 4

Узумно для такого рода вещей я использую apache-commons-lang StringUtils # join. Хотя на самом деле не сложно написать все эти функции полезности, всегда лучше использовать существующие проверенные библиотеки. Apache-commons полон полезных вещей, подобных этому!

Ответ 5

Если вы используете итератор, а не для... каждый ваш код может выглядеть так:

StringBuilder builder = new StringBuilder();

Iterator<Map.Entry<MyClass.Key, String>> it = data.entrySet().iterator();

while (it.hasNext()) {
    Map.Entry<MyClass.Key, String> entry = it.next();

    builder.append(entry.key())
    .append(": ")
    .append(entry.value());

    if (it.hasNext()) {
        builder.append("\n");
    }
}

Ответ 6

Это, наверное, лучший пример...

final StringBuilder buf = new StringBuilder();
final String separator = System.getProperty("line.separator"); // Platform new line
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
    builder.append(entry.key())
       .append(": ")
       .append(entry.value())
       .append(separator);
}
// Remove the last separator and return a string to use.
// N.b. this is likely as efficient as just using builder.toString() 
// which would also copy the buffer, except we have 1 char less 
// (i.e. '\n').
final String toUse = builder.substring(0, builder.length()-separator.length()-1);

Ответ 7

Здесь моя сжатая версия, которая использует свойство длины StringBuilder вместо дополнительной переменной:

StringBuilder builder = new StringBuilder();

for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    builder.append(builder.length() > 0 ? "\n" : "")
           .append(entry.key())
           .append(": ")
           .append(entry.value());
}

(Извинения и благодарность как Джону, так и Джоулю за "заимствование" из их примеров.)

Ответ 8

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

public class CustomStringBuilder {

final String separator = System.getProperty("line.separator");

private StringBuilder builder = new StringBuilder();

public CustomStringBuilder appendLine(String str){
    builder.append(str + separator);
    return this;
}

public CustomStringBuilder append(String str){
    builder.append(str);
    return this;
}

public String toString() {
    return this.builder.toString();
}

}

Реализация, такая как:

CustomStringBuilder builder = new CustomStringBuilder();

//iterate over as needed, but a wrapper to StringBuilder with new line features.

builder.appendLine("data goes here");
return builder.toString();

У этого есть некоторые недостатки:

  • Написание кода, который обычно не ориентирован на "домен/бизнес"
  • Не использовать стандартное решение с открытым исходным кодом, например: StringUtils.join
  • Принудительно поддерживать класс, который обертывает класс JDK, который является окончательным, и, следовательно, обновляет требуемые длительные сроки.

Я пошел с решением StringUtils.join для итерации над коллекциями и даже создания шаблонов метода легкого построения кода.

Ответ 9

Предполагая, что ваш цикл foreach проходит через файл, чтобы просто добавить новую строку в каждую строку и удалить последнюю новую строку, когда ваш цикл завершен.

Ответ 10

Не уверен, что это лучше всего, но это более простой способ:

проведите все значения и добавьте \n, как правило, в stringbuffer. Затем сделайте что-то вроде этого

sb.setLength(sb.length()-1); 

Ответ 11

Здесь метод соединения для дополнения split будет полезен, потому что тогда вы можете просто присоединить все элементы, используя новую строку в качестве разделителя, и, конечно же, она не добавит новую строку до конца результата; что я делаю это на разных языках сценариев (Javascript, PHP и т.д.).

Ответ 12

Если вы используете Class Separator, вы можете сделать

StringBuilder buf = new StringBuilder();
Separator separator = new Separator("\n");
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
    builder.append(separator)
       .append(entry.key())
       .append(": ")
       .append(entry.value());
}

Сепаратор печатает в пустой строке при первом использовании, а разделитель - во всех последующих целях.

Ответ 13

Ха! Благодаря этому сообщению я нашел другой способ сделать это:

public static class Extensions
{
    public static string JoinWith(this IEnumerable<string> strings, string separator)
    {
        return String.Join(separator, strings.ToArray());
    }
}

Конечно, это сейчас на С#, и Java пока не поддерживает метод расширения, но вы должны быть в состоянии адаптировать его по мере необходимости — главное - использование String.Join в любом случае, и я уверен, что у java есть аналог для этого.

Также обратите внимание, что это означает выполнение дополнительной итерации строк, потому что вы должны сначала создать массив, а затем перебрать его, чтобы построить свою строку. Кроме того, вы создадите массив, в котором с некоторыми другими методами вы сможете обойтись с помощью IEnumerable, который хранит только одну строку в памяти за раз. Но мне очень нравится дополнительная ясность.

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

Ответ 14

Пусть библиотеки делают это для вас.

import com.sun.deploy.util.StringUtils;

а также многие другие имеют StringUtils, который имеет метод соединения. Вы можете сделать это в одной строке:

StringUtils.join(list, DELIMITER);

Но для большего контекста, вот как вы могли бы сделать это с помощью hashmap.

public static String getDelimitatedData(HashMap<String, String> data) {
    final String DELIMITER = "\n"; //Should make this a variable
    ArrayList<String> entries = new ArrayList<>();

    for (Map.Entry<String, String> entry : data.entrySet()) {
        entries.add(entry.getKey() + ": " + entry.getValue());
    }

    return StringUtils.join(entries, DELIMITER);
}

Ответ 15

Используйте JDK-строку, соединяющую API:

String result = data.stream()
    .map((k,v) -> String.format("%s : %s", k, v)
    .collect(Collectors.joining("\n"));

Ответ 16

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

Вот пример кода

StringBuilder sb = new StringBuilder();

for (Map.Entry<String,String> entry : myMap.entrySet()) {
    builder.append(entry.key())
           .append(": ")
           .append(entry.value())
           .append("\n");
}
return sb.toString().trim();