string.Joinを使ってサクッと複数行のデータを表示

C#

こんにちは、働くC#プログラマーのさんさめです。

突然ですが、
このようなMessageBoxを出したいと
思ったことはありませんか?

複数のデータを削除するボタンなどを実装したときに、
最終確認として表示する確認ダイアログです。

この時、地味に面倒なのが、
リストの各データの名前を1つの文字列に結合することです。

この手の処理で最初に考え付くのは、
まずstringやStringBuilderの変数を1つ用意して、
リストをforeachで回して文字列に足していく…。

といったものではないでしょうか。

var message = string.Empty;
foreach (var item in list)
{
    var label = item.Name + item.Id.ToString();
    message += $"{label}\n";
}
MessageBox.Show(message);

でも、これって煩わしいことが沢山ありますよね。

  • たかが文字列結合の割にコードの行数が多くなる
  • 改行が最後の文字列の後にも入ってしまうのが気になる
  • 大量の場合は途中で打ち切りたいが、
    そのためには数を数えなければ…
さんさめ
さんさめ

意外と考えること多いな…

実は、こういう時に使える、
string.Joinというメソッドが、
組み込みのメソッドとしてあるんです。

本記事では冒頭の削除確認ダイアログのような
複数行出力の事例を通して、
string.Joinのよくある使い方を紹介します。

スポンサーリンク

string.Joinは文字列リストを連結するメソッド

改めての紹介になりますが、
string.Joinは、
「指定したリスト」を「指定した文字列」で、
連結して1つのstringを返す、
組み込みの静的メソッドです。

組み込みなので、
特定のライブラリをusingしたりすることなく、
すぐに使えます。

以下は冒頭のコードを、
string.Joinを使って書いたサンプルコードです。

var message = string.Join("\n", list.Select(x => x.Name + x.Id.ToString()));
MessageBox.Show(message);

なんと、文字列を連結する部分のコードが
1行になってしまいました。

代わりに1行でやってることが複数になってしまったので、
大きく2つに分解して見ていきます。
まず、最初のところですね。

string.Join("\n", ~~~

ここは、区切り文字を指定しています。
文字列(string)で指定することも、
文字(char)で指定することもできます。

私はダブルクォーテーション(”)の方が打ちやすいので、
特に考えずに文字列で指定することが多いです。

次に、この部分です。

~~~ , list.Select(x => x.Name + x.Id.ToString());

ここでは、LINQのSelectメソッドを使って、
リストの個々の要素を文字列に変換しています。

LINQは便利です。使わないと勿体ない。

…ちょっと話が逸れましたが、
これだけです。超簡単ですね。

慣れるまではその都度調べて思い出しながら
書くことになるかとは思いますが、
慣れてスラスラ書けるようになると快適ですよ。

foreachと違って最後に余計な文字が入らない

結構重要ポイントなのですが、
string.Joinは「リストを指定文字列で結合
するメソッドなので、
当然、要素と要素の間にしか指定文字列は入りません。

つまり、こういうことです。

実行結果もついでに見てみましょうか。

foreachだと最後に余計なカンマが
おまけでついてきちゃいますが、
string.Joinはそういうことはありません。
スマートです。

途中の切り上げもLINQと組み合わせれば簡単

最初の例に見せたMessageBoxですが、
大量にデータを選択されてしまったときなどは、
MessageBoxが縦長になりすぎる恐れがあります。

絶望のMessageBox

そのため、適当な数で切り上げて、
「他〇〇個のファイル」
といった表示に切り替えてあげるのが親切です。

そんな時はLINQのTakeが役に立ちます。

以下はサンプルコードです。

var list = Enumerable.Range(0, 1000)
    .Select(x => Path.GetRandomFileName())
    .ToArray();
var message = string.Join("\n", list.Take(10));
if (list.Length > 10)
{
    message += $"\n他{list.Length - 10}個のデータ";
}

少し長くなりましたが、
1つ1つを見れば
何をやっているかが見えてきます。

重要なのは、

list.Take(displayMaxNum)

のところです。
Takeメソッドを使って、最初の10個だけを取り出し、
それを表示用のメッセージとして、
string.Joinで結合しています。
(もちろん、10個に満たない場合は、
存在する分だけ結合されます)

次に、if文とその中身ですね。

if (list.Length > 10)
{
    message += $"\n他{list.Length - 10}個のデータ";
}

10個を超えた場合のみ
あと何個あるのかを追加のメッセージとして含めています。

実行結果は次のような感じです。

良い感じですね。

同じことをforeachのやり方でやろうとすると、
数を数えあげるために、forに書き直したり、
break文が必要になったり、
かなりややこしい記述が必要になります。

1回書く分には全然なんとでもなるのですが、
保守性はかなり下がります…。

string.Joinを使った方が、
やりたいことに対してシンプルに書けるという紹介でした。

まとめ

まとめです。

  • 複数のデータを1つの文字列にして出力するのは
    意外と面倒な処理
  • string.Joinは文字列を結合するメソッドで、
    そういうケースに威力を発揮
  • 元が独自クラスのリストなら、
    Selectと組み合わせると強力
  • 途中で切り上げるならTakeを活用する

最後までお読みいただき、ありがとうございました。

関連記事

独自クラスを文字列に加工する時、
string.Formatとか使ってるコードは現存していますか?

文字列補間の書き方に置換した方が読みやすく
例外も起きにくいのでおススメです。

コメント

タイトルとURLをコピーしました