33

我正在遍历 HashMap(有关更多详细信息,请参阅我之前的问题)并构建一个由 Map 中包含的数据组成的字符串。对于每个项目,我都会有一个新行,但对于最后一个项目,我不想要新行。我怎样才能做到这一点?我在想我可以通过某种方式检查条目是否是最后一个条目,但我不确定如何实际做到这一点。

谢谢!

4

16 回答 16

73

将您的思维过程从“除了最后一次之外都添加换行符”更改为“除了第一次之外都添加换行符”:

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());
}
于 2009-01-15T20:27:26.817 回答
72

一种方法(向 Jon Skeet 道歉,因为他借用了他的部分 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";
}
于 2009-01-15T20:30:54.500 回答
13

那这个呢?

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

必须道歉,并感谢 Jon 和 Joel 从他们的例子中“借鉴”。

于 2009-01-16T14:29:34.303 回答
9

通常对于这类事情,我使用 apache-commons-lang StringUtils#join。虽然编写所有这些实用程序功能并不难,但重用现有的经过验证的库总是更好。Apache-commons充满了类似的有用的东西!

于 2009-01-15T20:37:09.493 回答
5

如果您使用迭代器而不是 for...each 您的代码可能如下所示:

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");
    }
}
于 2009-01-15T21:27:55.803 回答
3

这可能是一个更好的例子......

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);
于 2010-11-25T00:19:23.217 回答
2

这是我的简洁版本,它使用 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());
}

(道歉并感谢 Jon 和 Joel 从他们的例子中“借鉴”。)

于 2009-01-16T14:15:48.930 回答
2

一种解决方案是为 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 解决方案来迭代集合,甚至在代码中构建轻量级构建方法模式。

于 2011-05-12T20:23:18.167 回答
1

假设您的 foreach 循环遍历文件,只需在每个字符串中添加一个新行,并在循环退出时删除最后一个新行。

于 2009-01-15T20:27:49.293 回答
1

不确定这是否是最好的,但它是更简单的方法:

循环遍历所有值并将 \n 通常附加到字符串缓冲区中。然后,做这样的事情

sb.setLength(sb.length()-1); 
于 2009-01-15T20:29:04.957 回答
0

这就是为了补充 split 的 join 方法会派上用场的地方,因为这样您就可以使用新行作为分隔符来连接所有元素,当然它不会在结果末尾附加新行; 这就是我使用各种脚本语言(Javascript、PHP 等)的方式。

于 2009-01-23T15:39:52.310 回答
0

如果你使用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());
}

分隔符在第一次使用时打印为空字符串,而分隔符在所有后续使用时打印。

于 2009-03-05T23:45:02.613 回答
0

哈!感谢这篇文章,我找到了另一种方法来做到这一点:

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

当然这是在 C# 中,Java 将(还)不支持扩展方法,但你应该能够根据需要调整它——主要是String.Join无论如何使用,我相信 java 有一些类似的为了那个原因。

另请注意,这意味着对字符串进行额外的迭代,因为您必须首先创建数组,然后对其进行迭代以构建字符串。此外,您创建数组,使用其他一些方法,您可能可以使用一次仅在内存中保存一个字符串的 IEnumerable 来解决。但我真的很喜欢额外的清晰度。

当然,鉴于扩展方法功能,您也可以将任何其他代码抽象为扩展方法。

于 2009-03-17T13:28:36.267 回答
0

让图书馆为您做这件事。

import com.sun.deploy.util.StringUtils;

以及许多其他人都有 StringUtils,它有一个 join 方法。您可以在一行中执行此操作:

StringUtils.join(list, DELIMITER);

但对于更多上下文,这里是你如何使用哈希图来做到这一点。

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);
}
于 2015-01-16T22:25:25.900 回答
0

使用 JDK 字符串连接 API:

String result = data.stream()
    .map((k,v) -> String.format("%s : %s", k, v)
    .collect(Collectors.joining("\n"));
于 2017-11-21T20:33:31.447 回答
0

如果您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();
于 2019-09-05T14:23:07.867 回答