【C#】C#プログラミングのイディオム(6章)配列とList<T>の操作
前回の続き
配列に対してはLINQを利用することが一番多いと思います。 LINQ以前はfor文やforeachで回しながら、該当の値を探したりしていたのですが、LINQを利用するとすっきり求めることができます。 利用の仕方を知った後に、利用していないソースを見ると「もったいないな〜」と思うようになれると思います。
テーマはこちら
- 要素の設定
- コレクションの集計
- コレクションの判定
- 単一要素の取得
- 複数要素の取得
- その他の操作
要素の設定
連続した文字列を設定する。 LINQならば
//List Enumerable.Repeat("設定したい値","設定したい数").ToList(); //配列 Enumerable.Repeat("設定したい値","設定したい数").ToArray();
LINQを使わないならば、forとかforeachかな。(でも書籍では非推奨と書いてある) Pythonだと、[num] * count でできるから楽チン
//連続した数値の場合 Enumerable.range(開始の値、作成数).ToArray(); こっちのほうが便利
コレクションの集計
LINQのメソッドで直感的に求めることができる。
//平均 var avarage = numbers.Avarage(); var avarage = books.Avarage(x => x.Price); //合計 var sum = numbers.Sum(); var sum = books.Sum(x => x.Price); //最小値 var min = numbers.Min(); var min = numbers.Max();
どれも、LINQのメソッドで指定できる。条件を細かくしたい場合は、whereを利用すれば、条件指定できます。 LINQを利用しない場合、for や foreachで繰り返しながら、if文などのロジックを書きます。
コレクションの判定
該当のデータがあるか、ないかのチェックを行います。 LINQを利用すると便利。 SQLっぽく使えるのがよい。
//条件にあう要素があるか bool exists = books.Any(x => x.Price < 1000); //全ての要素が条件に該当するか bool exists = books.All(x => x.Price < 1000);
単一要素の取得
アプリを作る時によく使うのがこの関連。 比較よりも該当するデータを取得する機能の方がよく使います。
/*Firstも最初の一件を取得だが、見つからないと、InvalidOperationExceptionが発生する。 値が見つからない場合にDefaultの値を戻すこれらのメソッドを必ず使う*/ //最初の1件だけ var text = books.FirstOrDefault(x => x.Price == 1000); //最後の1件だけ var text = books.LastOrDefault(x => x.Price == 1000); //最初の位置を求める ⬅︎ これはメソッドの方がいいようです。確かに、LINQで取得は見たことがない。。。 var index = words.FindIndex(x => x < 0);
複数要素の取得
条件で指定するのはwhereメソッドを利用します。 書籍に書いてあるTakeメソッドは使ったことなかった。該当件数のみほしいとかなかったので。 取得した後、for文で回すよりはTakeの方がいいかも
//5より大きいのを最大3つ取得。3つなくても、取得した数だけ戻す。 var result = numbers.where(x => x > 5) .Take(3);
条件分岐のwhileに相当する TakeWhileやSkipWhileも記載がありますが、あまり使わないなー。
その他の処理
他にも単一化のDistinct()やOrderByなど、SQLぽいメソッドがたくさんあり、使えると便利です。 本書のColumnに記載の「要素の削除」については、そうだよね。と納得する部分でした。
リストや配列の中から、一部のデータを除外する時にforを利用しようとする人を見たことがあります。 forないでインプットにしている要素を削除すると、forの添え字が崩れ、正しくループしなかったり、 InvalidOperationExceptionが発生します。 そのため、forを利用するのではなく、 * 既存の要素をremoveAllで削除 * 取得したい値だけど別の変数に移動する のどちらかを利用して対処するのが良いです。
この章も知っていると便利というものが多かったです。 C#を使うならLINQをしっかり覚えよう!といった感じの章でした。
つづく
【C#】C#プログラミングのイディオム(5章) 文字列の操作
の続き
次は文字列の操作。 知っているか知っていないかでコーディングできるできないが結構別れる。 書籍に記載のように見やすくもかけるし、ゴリゴリもかけるので、できればすっきり見やすく書けるようになりたいです。
記載されているテーマは以下でした。
- 文字列の比較
- 文字の判定
- 文字列の検索と抽出
- 文字列の変換
- 文字列の連結と分割
- その他文字列操作
今回も気になった部分をピックアップします。
文字列の比較
よく入門時に、オブジェクトが同じものかどうかと中身の値が同じかどうかの比較で頭を悩ます部分がありましたが、 この本の説明は「値」の比較ということで説明されています。
比較 | 書き方 | 備考欄 |
---|---|---|
単純比較 | str1 == str2 | |
大文字小文字区別無し | String.Compare(str1, str2 , ignoreCase : true) | ignoreCaseの書き方は C# 4.0以降 trueだけでもかける |
ひらがなカタカナ区別無し | String.Compare(str1, str2 , new CultureInfo('target language'), CompareOptions.IgnoreKanaType) | ignoreCaseの書き方は C# 4.0以降 trueだけでもかける |
全角半角区別無し | String.Compare(str1, str2, new CultureInfo('target language') , CompareOptions.IgnoreWidth) |
先にUpperCaseとか使って、無理やり大文字にとかにして、比較していたな〜と。
MSDNのサイトに書く説明の記載がありました。
文字列の判定
MSDNのStringメソッドを見ても、多い!と覚えきれない。ただ、「こんなことできないかな?」と思った時に確認はしたいですね。
普段よく使うのは
String.IsNullOrEmpty(str) str.Contains("strにあるか調べたい文字列") str.Contains('strにあるか調べたい文字')
文字列の検索と抽出
文字列の抽出が使うことが多い str.Substring(startIndex, cut_length) ただ、こういう時に記載する開始位置にマジックナンバーとして、ハードコーディングはして欲しくないですね。 先にconstでもいいから固定値で定義しておいて、その変数名から設定している意味を表せるようにするとよいです。
文字列のメソッドはそのまま出力とかするのならば、str.xxxでよいが、 結果を使いまわすというときは別の変数に値をおく必要があります。 当たり前じゃん、なんだけど、初学者のうちはやってなくて、値が取れないという人を見かけるので。
文字列の連結と分割
単純には var name = "str1" + "str2" と + 演算子です
メソッドを利用するなら String.Join(separator, array) ・・ separatorに指定した文字で、文字をつける
str.split(separator) ・・・ separatorsに指定した文字で、文字列を分割し、配列型にする
stringなど文字列は不変オブジェクト そのため、仮に str = str + "aaa"; としても、左辺のstrと右辺のstrは別のメモリ番地を使っている。 やりすぎると、それだけでメモリを多めに使ってしまう。
代わりにStringBuilderを利用することで、解消できます。 var sb = new StringBuilder(); sb.Append("hoge") とするとsbで使用しているメモリ番地の値に"hoge"を追加します。
書籍に記載の指針は ### 繰り返し処理をしない場合は + 演算子 ### foreachなどで、文字列連結を繰り返す場合、StringBuilder ### 繰り返す回数が少ない場合は + 演算子 を使う
その他の文字列操作
pythonなどと同じく、文字列で定義されたものは
foreach(var c in str){ Console.WriteLine(c + ','); }
とすれば、strに設定した文字を一つずつ出せる。
文字列へ変換
hoge.ToString();
とすれば、hogのものを文字列に置き換えられる。 また、ToString('format') またはstring.format(フォーマットの型、hoge) で書式変換できる。
c# 6.0以降で利用できるものが増えてもいる。 せっかく便利なメソッドやLINQでの指定ができるので、使わない手はない。
つづく・・・
【C#】C#プログラミングのイディオム(4章) 基本イディオム
の続きです。
3章までは準備編となっていて、4章からは基本イディオムの紹介
仕事で使っているのが、C# 5.0(Visual Studio 2013)なのと、今までC#のバージョンを折ったことなかったので、C# 6.0以降で利用できるイディオムを初めて知った。
知っているのと知らないのでは、自分のコーディングのスピード、メンテナンス性と他人のソースをレビューする速度や品質が変わるので、使える部分は使いたいと思う。
記載されている基本イディオムの内容は以下のものでした。
可読性や保守性を考えた場合、こう書いた方がいいよねということ記載されています。
気になった部分や「そうなんだ」と思った箇所を中心に書きます。
初期化
配列の初期化
var names = new List<string> { "Tokyo", "Nagoya", "kyoto", };
最後の項目の後ろにカンマをつけておく。
なんで、最後にカンマつけるのだろうとよく思っていた。
実際、カンマはつけなくてもコンパイルは通ります。
他の記事とか見ていますと、項目とカンマをセットにして値を取り出したいとか
した場合、ついていた方がいいよね、と記載されていました。
配列というかenumで定義する時に最後にカンマつけるているケースを見かけます
オブジェクトの初期化
public class Person{
public string Name { get; set; }
public string Birthday { get; set; }
public string PhoneNumber { get; set; }
}
var person = new Person
{
Name = "hogehoge",
Birthday = "20010910",
PhoneNumber = "xxx",
};
オブジェクトを初期化するときはこう書くけど、入門書や少し古い本だと
person.Name = "hogehoge";
と書いてあるもんもありますよね。
書籍に書いてある通り、初期化コードの間に、無関係なロジック入れる人がごくごくたまにいるので、。
分岐、比較
returnの扱い方
時々、「1メソッドにreturnは一つしか書いてはダメ」みたいな教えを受けた人に出会い、途中でreturn を書けば、見やすいのに。
if ( xxx ) {
if ( xxx) {
if(xxx) {
}
}
}
return value;
みたいな感じのifのネストもしくはフラグ使いまくり・・・のソースに出くわします。
意味合いが同じなら、途中でreturn を書いて、ソースを見やすくしてほしいな。
繰り返し
要素の数だけ繰り返す
public void a(){
var nums = new List<int> { 1, 2, 3, 4, 5, };
nums.ForEach(n => Console.WriteLine(n));
}
LINQのForEachメソッドを利用するとこうかけるみたいです。
いつもforeach(var n in xxx) を使っているので、そういう書き方するんだという印象。
1文だけのそy理なら、ForEachメソッドで書くといいねと書いてありました。
条件演算子、null演算子
条件演算子
条件が複雑でない、戻り値が単純なら以下のように記述する。
var value = xxxx ? trueの値 : falseの値
条件演算子は見た目がすっきり!になりますが、条件が複雑であったり、戻り値に対する処理や値が多い場合はif文を使ってもらった方が、後々意味が通る。
合体演算子
.net 2.0で導入されているが、この書き方で描かれているのはお目にかかったことがない。
var message = hoge(code) ?? Default-value
null演算子
c# 6.0 から導入されている。c#5.0までしか見たことないので、お初。
hogeの値がない場合nullで返してくれる。
if(value == null){
return null;
}else{
}
と同等
プロパティ
読み取り専用プロパティ
プロパティのsetアクセサーをprivateの可視性にして定義するか、
setアクセサーをそもそも記述しないことで対応できる。
C# 6.0からは
public string Name => hoge + "" + xxx;
とすることで、読み取り専用のプロパティを作成できる。
参照型の読み取り専用プロパティ
上記のようにprivateで書いても、書き換えられないのは参照(メモリの)のみで、
参照先の値は変更できます。そのため、こちらが意図したい、値の変更を不可ということが実現できません。
コレクション自体を変更不可にするにはIReadOnlyList<type>,IEnumerable<type>を利用する。
public IReadOnlyList<int> hogeList { get; private set;}
メソッドに関する
可変長引数
params キーワード
ログの引数を与えたりする時に使ってます。
public void WriteLog(string messageFormat, params object[] args){
var s = String.Format(messageFormat, args);
WriteLine(s);
}
呼び出し元は
hoge.WriteLog("output format", time, user, action);
time,user,action など、個数に限らず、paramsを指定することで可変に設定可能
オーバーロードよりオプション引数
多態性でオーバーロードを見ることはありますが、C#に限らず、使われ始めているような。
method(int num, string message = "hogehoge", int count = 3);
呼び元
numは必ず指定する。他は指定していなければ、デフォルト値が設定されます。
結果、オーバーロードっぽく見えます。
method(3);
method(4, "hello");
method(6, "good", 3);
その他
逐語的リテラル文字
先頭に@を書きます。
var path = @"C:¥resource¥file.txt";
@を書くことで¥がエスケープ文字として認識されなくなります。
固定値で書くときはこれでいいのですが、データベースなどで設定している値をシステム、特にOSウィンドウの値などに設定すると、エスケース文字として¥が扱われることがあります。
その場合、かっこ悪いですが
'"' + path + '"' と切って、エスケープ文字として見られないように
前後にDouble Quotationを入れたりしています。
文字列を数値に変換
int.Parse(str)を利用すると、失敗した時にExceptionが発生して面倒なんですよ。
本書に記載のように先に失敗しないかをint.TryParse(str)で確かめておくと確かにいい感じです。
例外の再スロー
throw;だけです。
時々 throw ex;で書かれます。スタックトレースが消えるのでご勘弁・・です。
他にも書いてありますが、そこは書籍で確認で!
標準化という訳ではないですが、「こうやって常にコードを書く」と意識しておくことで、綺麗で、あとで見やすいコードになります。
次は5章 文字列の操作
<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;margin:0px 12px 1px 0px;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4774187585/restofwaterim-22/ref=nosim/" name="amazletlink" target="_blank"><img src="https://images-fe.ssl-images-amazon.com/images/I/51Q1LFkj2qL._SL160_.jpg" alt="実戦で役立つ C#プログラミングのイディオム/定石&パターン" style="border: none;" /></a></div><div class="amazlet-info" style="line-height:120%; margin-bottom: 10px"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4774187585/restofwaterim-22/ref=nosim/" name="amazletlink" target="_blank">実戦で役立つ C#プログラミングのイディオム/定石&パターン</a><div class="amazlet-powered-date" style="font-size:80%;margin-top:5px;line-height:120%">posted with <a href="http://www.amazlet.com/" title="amazlet" target="_blank">amazlet</a> at 18.09.09</div></div><div class="amazlet-detail">出井 秀行 <br />技術評論社 <br />売り上げランキング: 10,714<br /></div><div class="amazlet-sub-info" style="float: left;"><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4774187585/restofwaterim-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jpで詳細を見る</a></div></div></div><div class="amazlet-footer" style="clear: left"></div></div>
【C#】C#プログラミングのイディオム(3章) ラムダ式とLINQの基礎と1章(プログラミングの基礎)
図書館で本を借りて、
何気に、LINQを使っていたが、言語の進化の歴史については知らなかったので、そうだったんだ!という感じです。
この章ではラムダ式以前と以後について説明されております。
経緯は知らなかったので、メモメモ・・
1. メソッドに普通に引数を渡す
2. デリゲートによる実現
3. 匿名メソッドの利用
4. ラムダ式
3でいう、Countメソッドを次のように変えることができます。
4-1 まずは、そのままべたに書く
ラムダ式でかけるようになってから、delegateや匿名メソッドを活用して、「どうやって書こう」から、ラムダ式ですっきりかけるので、「何を書こう」に変わりました。
確かに、ラムダ式便利なんですよね。これあが実現されたLINQ to Objectを利用すれば、変数に対して、SQLっぽく扱えるので。以前みたいに、ゴリゴリコードをかかなくてよくなりましたから。
LINQ to Objectsの使い方
・System.Collections.Generic
・System.Linq
の名前空間を指定します。
例えば。
var names = new List<string>{
"America", "Brazil", "Italia", "China", "Japan"
};
IEnumerable<string> query = names.Where(x => x.Length <= 5);
利用する際、リンク演算子が「即時実行」なのか「遅延実行」なのかを知っておく必要があります。
演算子を定義した時の値で評価するのか、演算子を利用する場合の値で評価するのかの違いです。
即時実行したいのに、遅延実行で記載していると、取得したい値が取得できなかったりします。
---------------------------------------------
2020/10/24 追加 1章の話
class と struct
クラスは参照型、structは値型となる。
参照型はヒープ領域、値型はスタック領域に値が保持される
私自身、structを使っているプログラムをほとんど見たことがない。
メモリを効率的に使うということで、小さい値ならstructを利用するほうがいい。
大きい値を利用する倍、ポインタで参照を利用するclassをとなるが・・・。
書籍に記載の通り、structは見たことないんですよね。使っているのを。
ポインタとメモリと型(構造体)の関係 (2) - C言語 - 碧色工房
▪️学習している書籍
【振り返り】Redmineをソフトウェア開発に導入して2年使ってみて(初期の頃)
今のお客さんの開発に携わり、割とプロジェクト管理に関するルールなども自社ルールに縛られず、お客さんのルールにも縛られずに入れる環境であったので、Redmine入れて管理したいなと思い導入してから約2年。
やってみて、個人的に便利 or あと少し・・・ということを勝手に振り返ります。
ただ、結論的に言えることは「Excel」管理やMSProjectには戻れないなと。
自分がやりやすいやり方に今は行き着いているので、これが正解と捉えず、こういう例もあるんだと捉えていただければ幸いです。
(スクラムっぽくプロジェクトもスプリントも設けて実施していましたが、ここではRedmineの使い方のみに焦点を当てています。)
1.導入した経緯
これまで進捗の管理にはMS Excelを利用してくる場面が多かった。なんでプロジェクト管理の手法が旧態依然のまま誰もが、それに従っていたのかよくわからず、「ルール」という縛りにあがらうことできず過ごしてました。
そこで、まあある意味実験的にいろいろと試すことができる環境に置かれたものだから、「アジャイル」「Lean」というバズワード(まあ、2015年ごろ入れたので、もう普通に使われてますね)に引かれ、「まずは使ってみよう」と自分のチームとお客さんに宣言して利用し始めました。
※かんばんを壁に紙で貼るということも考えましたが、お客さん先で複数ベンダーが入っている関係上、セキュリティ上NGでしたので、Redmineを利用しました。
2.初期のころ
Redmineの入門本を購入し、デフォルトの機能のみで管理してました。
(今考えると無鉄砲で計画性がなかったなと反省・・・)
どう管理していたの??
「トラッカー」で作業を分類してましたここまでで良くなったの?
この管理でかつ、途中でRedmineとSVN連係も追加し、約1年はこの設定状態で管理をしました。
手持ちのチケット数が少ないとメンバも余裕があることと、自分自身のスケジュール管理もできていたのですが、追加・変更案件とテストによる指摘事項がチケットに混在してくると「どのチケットからやるの」「優先順位をどうつけるの」というのが錯綜し、若干パニック状態になりました。
また、内部管理はチケットやRedmineの内容で説明すればある程度状況の把握はできていましたが、第三者や上位の管理者に説明するときにスケジュールを数字化するのに一苦労しました。
チケット数の総数、消化数、残数。予定時間と実績時間から想定される予想残工数。バグ発生の予想数、消化予想工数から着地がどれくらいになるのか・・・。チケットから作成するのにデータを抽出し、こねこねしなければならず、プロジェクト管理が楽になったのか?というのが若干疑問でした。
しかし、とは言っても、Redmineに記載された内容がトレースできていたので、「書かれてさえいれば」何に困っていたのか。何がうまく言っていたのかを分析するのには大変助かりました。
つづく
メモ:文字列の部分分割とeval(数学パズルQ2)
今回のお題を実施するのには数値もしくは文字列の間に四則演算を入れなければならなかった。
そのため、自分は「部分参照とか文字列分割だね」と思い、
hoge[n,m] ・・・ nには開始位置(0開始)、mには終了位置を指定する
hoge.substring(n,m)・・・nには開始位置(0開始)、mには長さをしていする
として、取得した値をもとに四則演算を用いて書いていた。
しかし、いろいろな四則演算のパターンを書くのはすっきりしないなとと思い、ページをめくったら、evalを利用していた。
C#でやろうとすると自前でevalを作成するか、他のスクリプト言語(例えば、JavaScript)を利用するのも一つ手らしい。
書籍には逆ポーランド記法を利用するとも載っていた。
結構なソースコード量になると思われる・・・ので、作成しやすい言語で今は考える元しようと思う。。。
また、eval利用するとコンパイラを通してや、IDEを通じて、エラーチェックや警告が走らないのが欠点。
頭の体操?にはよさそうだが、実際にものを作成するときには慎重に利用することが必要に感じた。
文字列を実行時に処理するだけなので、人間系で事前に処理の正しさ(仕様と違うか、セキュリティ的に文字解析の結果が大丈夫か)が必要ですね。
メモ:進数の変換と文字列の反転(数学パズルQ1)
数学パズルをやり始めました。
仕事でソースをチェックすることはありますが、コーディングすることが少なくなってきているので、楽しみながら、パズルを解いてます。
最近扱っている言語が、RubyとC#なので、書きやすさってのが比較できないかなと。
Q1で利用したメソッド
進数の変換
hote.to_s(num) # numには変換したい進数
Convert.ToString(hoge,num) -- hogeには指定の数値、numには変換したい進数
文字列の反転
hoge.reverse
string.Join("" , hoge.Reverse())
普通にhoge.Reverse()を記述すると、Iteratorが戻り値になるため、文字列にならない。
また、配列に対して、Reverseをすると配列の添字の順番を逆で並び替えるということが行われる。
Q2へ続く