ワテの場合、C#のプログラミングではDictionaryをよく使う。
そんなDictionaryを使う上で、役に立つ小技を備忘録としてメモしておくことにした。
Dictionaryの中から特定のvalueを持つ項目を削除する方法
色々な方法があると思うが、こんなやり方が普通かなと思う。
var removeTargetLst = dic.Where(kv => kv.Value == value).ToList(); foreach(var item in removeTargetLst) { dic.Remove(item.Key); }
このコードの意味は説明しなくても分ると思うが、Dictionary が保持している Key, Value ペアのうち、Valueが特定の値 value の要素のみをList化して取り出す。
そのListをループしてDictionaryからその項目を除去すれば良い。
実際にやってみよう。
Dictionaryの中から特定のvalueを持つ項目を削除するサンプルC#
static void test1() { var dic = new Dictionary<int, string>{ { 0, "000" }, { 1, "111" }, { 2, "この要素を消したい"}, { 3, "333" }, { 4, "444" }, }; var value = "この要素を消したい"; dumpDic(dic, "削除前"); var removeTargetLst = dic.Where(kv => kv.Value == value).ToList(); foreach (var item in removeTargetLst) { dic.Remove(item.Key); // ここで削除する。Keyを指定して削除出来る。 } dumpDic(dic, "削除後"); } static void dumpDic<TKey, TValue>(Dictionary<TKey, TValue> dic, string msg) { Console.WriteLine("{0}", msg); Console.WriteLine("count:{0}", dic.Count); foreach (var pk in dic) { var key = pk.Key; var val = pk.Value; Console.WriteLine("key:->{0}<-, val:->{1}<-", key, val); } }
実行例(Dictionaryの中から特定のvalueを持つ項目を削除する)
削除前 count:5 key:->0<-, val:->000<- key:->1<-, val:->111<- key:->2<-, val:->この要素を消したい<- key:->3<-, val:->333<- key:->4<-, val:->444<- 削除後 count:4 key:->0<-, val:->000<- key:->1<-, val:->111<- key:->3<-, val:->333<- key:->4<-, val:->444<- 続行するには何かキーを押してください . . .
Count, Count(), LongCount() とは何や?
C#ではDictionaryやListや配列などの要素の数は Count プロパティで取得出来る。
さて、恥ずかしながら最近まで知らなかったのだが Count() というのも有る。
CountプロパティではなくてCount()メソッドだ。まあ、日本語で言えば関数の事だな。
適当に Dictionary を作成して、その辞書変数dic に対して
dic.Count(
まで入力すると、Visual Stuidoのインテリセンスが以下のようなメッセージを表示してくれる。
つまり dic という変数に対して dic.Count() や dic.Count(なんちゃら) と言うメソッドがある事を教えてくれる。
こちら↑はカッコ内になんちゃら引数を取るメソッドだ。
まず、
dic.Count プロパティ
dic.Count() メソッド
は同じ値になる。どちらもdicの要素数を取得出来る。
dic.Count(なんちゃら) 引数ありのメソッド
とすれば、その「なんちゃら」と言う条件に一致する要素数のみ数える事が出来るのだ。
こんな感じか。
例えば Keyが 1 の要素のみ数える場合はこうなる。
var count = dic.Count(x => x.Key == 1);
なるほど、そう言う事か。
では、もっとややこしい条件にマッチした要素を数えたい場合には同じくカッコの中に条件をずらずらと書けば良いが、それだと無理がある。
それを別関数にしてスッキリ書くのが
Count<KeyValuePair<TKey, TValue>>(Func<KeyValuePair<TKey, TValue>, Boolean>)
の部分なのだが、何のことかサッパリ分からん。
百聞は一見に如かずなので簡単なサンプルを実行してみよう。
static void test2() { var dic = new Dictionary<int, string>{ { 0, "000" }, { 1, "111" }, { 2, "222" }, { 3, "333" }, { 4, "444" }, }; Func<KeyValuePair<int, string>, bool> myFunc = new Func<KeyValuePair<int, string>, bool>(myCountSpecial); var P_count = dic.Count; var M_count = dic.Count(x => x.Key == 1); var M_count2 = dic.Count(myFunc); Console.WriteLine("P_count ={0}", P_count); Console.WriteLine("M_count ={0}", M_count); Console.WriteLine("M_count2 ={0}", M_count2); } static bool myCountSpecial(KeyValuePair<int, string> kv_pair) { // 特定の条件に一致した要素のみ数える為の関数 var key = kv_pair.Key; var val = kv_pair.Value; if (key == 1) return true; else if (val == "333") return true; else return false; }
P_countではプロパティのCountで取得した値を出力。
M_countではメソッドのCount()でKeyの値が1の要素の数を出力。
M_count2ではメソッドのCount()からmyCountSpecial()を呼び出してその関数内で定義した判別方法にマッチした要素の数を数える。
この例では、key==1 か val==”333″ のどちらかの要素を数えている。
その実行結果
P_count =5 M_count =1 M_count2 =2 続行するには何かキーを押してください . . .
う~ん、まあ、何かの時に使える手法かな。
ちなみにLongCountとは Count結果が long(8バイト整数)でリターンされるようだ。そのまんまの命名だな。ワテも良くやる。
Func, Action, Predicate
C#には所謂 Func, Action, Predicate と言う(ワテにとっては)似たような仕組みがあるのでややこしい。
三つともにdelegate(デリゲート)と言う機能だ。
ここでは Func を使った訳だ。
ちなみに、ワテの理解では
- Func は戻り値がある。LINQでよく使う。
- Action は戻り値が無い。LINQではあまり使わない?
- Predicate は良く知らん。Funcみたいに戻り値がある。
だ。間違っているかもしれない。
参考までにWikipediaからデレゲートの説明を一部引用すると以下の通り。
デリゲートは、オブジェクトへの参照と関数オブジェクトへの参照をペアにして持つものである。オブジェクト指向プログラミングとしては、メソッドをカプセル化するクラスとも言える。型安全であるという特徴がある。
C++の「メンバ関数を指すポインタ」や、Object Pascal(Delphi)の「インスタンスのメソッドへのポインタを格納する、メソッドポインタ」と同様のものである(DelphiもC#もアンダース・ヘルスバーグによる設計である)。
また、Microsoft Visual J++も、Javaと非互換のデリゲートを導入したが、.NET Frameworkのデリゲートはこれらを発展させたものである。
デリゲートは主に、イベント処理での活用(コールバック処理のカスタマイズ)を想定している。Javaなどでのインターフェイスを利用したイベント処理と比べ、メソッド名を自由に宣言できる、振る舞いをカスタマイズするためにインターフェイスの実装やスーパークラスの継承を行なう必要がない、などの利点がある。
引用元 https://ja.wikipedia.org/wiki/デリゲート_(プログラミング)
下線強調はワテが付けた。
何回読み返してもオブジェクト指向の専門用語が多数出て来るので、さっぱり分からん。
まあ、要するにCやC++の関数ポインタみたいなもんか?
良く分からんので取り敢えずそう言う理解にしておこう。
つづく
マイクロソフトの公式解説書って言うくらいだから、この本で勉強すれば完璧かも。
でもワテは読んでいない。
コメント
var removeTargetLst = dic.Where(kv => kv.Value == value).ToList();
foreach(var item in removeTargetLst)
{
dic.Remove(item.Key);
}
ToListすると遅延評価の意味ないですね
aaaaさん、
コメントありがとうございました。
>ToListすると遅延評価の意味ないですね
そうですね。でも私にはこの例のようにToListして削除対象要素のリストを作成するやり方が分かり易いので使っています。
ちなみにToListせずにdictionaryの要素を削除する方法はあるのでしょうか?その辺りは詳しく調べていないのでもしご存じでしたら教えて頂けると有難いです。