HashMap を反復処理して (詳細については、以前の質問を参照してください)、Map に含まれるデータで構成される文字列を作成しています。項目ごとに改行しますが、最後の項目については改行したくありません。どうすればこれを達成できますか?エントリが最後のエントリかどうかを確認するために何らかのチェックができると思っていましたが、実際にそれを行う方法がわかりません。
ありがとう!
思考プロセスを「前回を除くすべての改行を追加する」から「初回を除くすべての改行を追加する」に変更します。
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());
}
1つの方法(Javaコードの一部を借用してくれたJon Skeetに謝罪します):
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";
}
これはどうですか?
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 の例から「借用」したことへの義務的な謝罪と感謝。
通常、これらの種類のものには、apache-commons-lang StringUtils#joinを使用します。これらすべての種類のユーティリティ機能を作成することはそれほど難しいことではありませんが、既存の実績のあるライブラリを再利用することをお勧めします。Apache-commonsはそのような便利なものでいっぱいです!
for...each の代わりに iterator を使用すると、コードは次のようになります。
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");
}
}
これはおそらくより良い例です...
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);
これは、追加の変数の代わりに StringBuilder の length プロパティを使用する私の簡潔なバージョンです。
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 の例から「借用」したことについて謝罪し、感謝します。)
1 つの解決策は、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 ソリューションを使用して、コレクションを反復処理し、コード内で軽量のビルド メソッド パターンを構築しました。
foreachループがファイルを通過して、すべての文字列に新しい行を追加し、ループが終了したときに最後の新しい行を削除するとします。
これが最善かどうかはわかりませんが、より簡単な方法です。
すべての値をループし、通常は文字列バッファに\nを追加します。次に、このようなことをします
sb.setLength(sb.length()-1);
クラスセパレータを使用する場合は、次のことができます
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());
}
セパレータは、最初の使用時に空の文字列で印刷され、それ以降のすべての使用時にセパレータが印刷されます。
ハ!この投稿のおかげで、これを行う別の方法を見つけました。
public static class Extensions
{
public static string JoinWith(this IEnumerable<string> strings, string separator)
{
return String.Join(separator, strings.ToArray());
}
}
もちろん、これは現在 C# であり、Java は (まだ) 拡張メソッドをサポートしていませんが、必要に応じて適応させることができるはずString.Join
です。そのために。
また、これは文字列の追加の反復を行うことを意味することに注意してください。最初に配列を作成してから、それを反復して文字列を作成する必要があるためです。また、配列を作成します。他の方法を使用すると、一度に 1 つの文字列のみをメモリに保持する IEnumerable を使用できる場合があります。しかし、私は余分な明快さが本当に好きです.
もちろん、拡張メソッド機能があれば、他のコードを拡張メソッドに抽象化することもできます。
ここで、split を補完する join メソッドが役立ちます。これは、新しい行をセパレーターとして使用してすべての要素を結合でき、もちろん結果の最後に新しい行を追加しないためです。 ; それが、さまざまなスクリプト言語 (Javascript、PHP など) で行う方法です。
これは図書館にお任せください。
import com.sun.deploy.util.StringUtils;
他の多くのものと同様に、join メソッドを持つ StringUtils があります。これは 1 行で実行できます。
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);
}
空白を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();