CSV分割ツールを自作しよう!(第6回・リライト編)

プログラミング入門
この記事は約5分で読めます。

1つの処理を実現する際、様々な手順(アルゴリズム)が考えられますが、前回はその一例として異なるアルゴリズムを紹介しました。

今回は、プログラムの書き方にも様々なパターンがあるという事を紹介したいと思います。

Google検索すると、同じ言語で同じ事をしているにもかかわらず、ずいぶん書き方が違う事が有ります。

その一例としてCSV分割ツールをリライトしていみました。

ソースコード

リライトした全体のプロジェクトは下記からダウンロード可能です。

ソースコード全体は以下の通りです。

最初のソースと見比べないと良く分からないかもしれませんね。

特長としては、Linq、ラムダ式、ローカル関数という2つの技術を使ってるという点です。

Linqとは

Linqは、Language Integrated Query の略で、マイクロソフトのサイトでは「統合言語クエリ」とも書かれています。

簡単に言うと、配列などのデータに対して、データベースで使われているSQLの様な書き方で、抽出や加工を行えるようにする拡張機能という解釈になろうかと思います。

Listや配列形式のデータに対してデータを加工したり、特定の条件に合致するデータだけを抜き出したりする場合、通常は forループを使います。

例えば、下記は先頭が “TEL:”から始まる行を抜き出すサンプルですが、Linqで書くと1行で書くことが出来ます。

ソースコード量が減るだけでなく、1行に凝縮されることで、中身が直感的に分かりやすくなるという特徴があります。

Linqはネスト(何段にも重ねて記述)が可能であり、抽出した結果から更に加工したり、別の条件で絞り込む事もできるため、やり過ぎると逆に可読性が悪化することもありますが、適度な利用は可読性向上に役立ちます。

ラムダ式とは

「記述した部分だけで有効な名前の無い関数」という表現が分かりやすいかと思います。

通常、関数(メソッド)はpublicやprivate、戻り値の型、関数名、引数の型、引数などを定義することで、初めて使える様になります。

ラムダ式は、このような限定的な場所で用いる関数の定義を簡略化したもので、

(型 引数名、型 引数名、・・・) => { 処理1; 処理2; ・・・ return 戻り値; }

という風に記述します。

ラムダ式はLinqやイベントハンドラで使われることが多く、先ほどのLinqで言うと、青い斜め文字の部分がラムダ式になります。

List result = lines.Where(i=>i.StartsWith(“TEL:”)).ToList();

Linqで使われているのと少し書き方が違いますね。

本来は下記の様に書くのが正しいような・・・

List result = lines.Where((string i)=>{ return i.StartsWith(“TEL:”);}).ToList();

そうなのですが、引数が1つで引数の型が推測できる場合は、引数名以外は省略可能です。

また、{ }内の処理が1つの場合も { } と return は省略可能です。

以上のことから、Linqで使用されている場合は、省略して書くことが一般的になっています。

ローカル関数とは

ローカル関数は、関数(メソッド)の中に記述するローカルな関数です。

通常の関数(メソッド)は、privateならクラス内のメソッドから、publicならクラス外から呼び出されますが、ローカル関数は定義した関数(メソッド)以外から使用することが出来ません。

また、関数(メソッド)内で定義した変数は、そのままローカル関数内で参照可能な点が異なります。

主な変更点

それでは、主な変更点を見てみましょう。

上がリライト前の記述、下がリライト後の記述になります。

画面からの数値変換に三項演算子

前は3行でしたが、今回は3項演算子を使って1行になっています。

3項演算子は、条件式が true なら値1を、false なら値2を返す演算子です。

(条件式)? 値1 : 値2

int.TrpParse メソッドは、引数に渡された文字列が数値に変換できれば trueを返しますので、false の場合は初期値である 0 を返すようにしています。

ループ処理のLinq化

次は、ヘッダ行を別変数にコピーする部分です。

Linqとラムダ式を使って、1行になりました。

末尾に ToArray() メソッドを呼び出していますが、これは結果を文字列配列に変換するためのメソッドです。

DivideSaveにローカル関数

行数をカウントし、分割行数に達したらファイルに保存する処理は、ループ内とループ終了後の2か所ありました。

リライト後は、この部分をローカル関数化しています。

これに伴い、ファイル名を生成する部分も、ローカル関数内に収めました。

ダイアログ表示の簡略化

ダイアログ表示の部分は、クラスのインスタンス生成と同時にプロパティに初期値をセットするとともに、ダイアログからの戻り値を三項演算子で処理することにより、ソースコードを半分にしました。

クラスのインスタンス生成時、プロパティに初期値を設定するには、次の様に記述します。

クラス名 変数名 = new クラス名(){ プロパティ1 = 初期値1,プロパティ2 = 初期値2,・・・};

今回は、以下の様に FileNameプロパティにuxOutputFolderコントロールのTextプロパティの値を設定しています。

まとめ

同じアルゴリズムですが、ちょっとした書き方のテクニックを使う事で、ソースコード量が減るとともに、プログラムの読みやすさも向上しました。

これ以外にもリライト可能な部分はありますが、それは次の機会に譲りたいと思います。

今回の記述方法はよく使うものなので、どんどん使って自分のものにしていきましょう。

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