ラムダ式が便利すぎて生きるのが辛い

2010.06.11 金 13:05:23

VS2008に搭載されたC# 3.0の大きな機能の一つ、ラムダ式。

従来での匿名デリゲートによる記述から、冗長な部分をごっそり取り除くことでより簡潔な記述ができるようになります。
これにより、簡単なことを簡単に書くという当たり前だけどなぜか他ではできないことができるようになります。

ラムダ式にもいろいろあるのですが、今回はProject Eularの問題61をもとに部分プログラムを示してみます。
私の場合はこれでもうおなかいっぱいです。

 

ということで、Project Eularの問題61。
http://odz.sakura.ne.jp/projecteuler/index.php?Problem%2061

とりあえずn角数(3≦n≦8)を適当な大きさ(maxとする)まで全て生成してしまわなければ始まらないでしょう。
ここではこのテーブル生成ルーチンを考えます。

判定を高速化するために、要素数maxのbool配列を用意し、フラグを立てていく戦略でいくことにしましょう。
つまり、bool[][] flagと用意し、たとえばflag[0][100]は100が三角数かどうか、flag[3][32]は32が六角数かどうか…flag[n][k]は値kが(n+3)角数であるかどうかを表す、というものです。

ここでラムダ式を使うとスマートに書けてしまいます。

        bool[][] flag = new bool[6][];

        Func<int, int>[] ts =

            {

                n => n * (n + 1) / 2,

                n => n * n,

                n => n * (3 * n - 1) / 2,

                n => n * (2 * n - 1),

                n => n * (5 * n - 3) / 2,

                n => n * (3 * n - 2)

            };

        for(int i = 0; i < 6; i++)

        {

            bool[] tmp = (flag[i] = new bool[max]);

            Func<int, int> f = ts[i];

            int k = 0, n = 0;

            while((k = f(n++)) < max)

                tmp[k] = true;

        }

Func<T1, T2>は、T1型の引数を受け取ってT2型の値を返すメソッドを示すデリゲートで、System名前空間に含まれています。 引数の数に応じてFunc<T1, T2, T3>などいくつか用意されています(ちなみに値を返さない場合にはAction<T>で)。

ここでn角数を求めるメソッドを一つ一つクラスメンバで書いてしまうのは論外でしょう。6回のループで回せなくなってしまいます。
ループで回せるようにデリゲート配列に入れてしまうのもぎこちなくて気持ち悪いですね。

匿名メソッドでこれを書こうとするならだいぶマシでしょう。

delegate(int n) {return n * (n + 1) / 2;}

三角数生成の関数はこんな風になります。な、長いぞ…

ここでラムダ式ではどうなるか。

n => n * (n + 1) / 2

式しか書いてありません。
nがパラメータ、右辺が値となるわけです。
型情報すら必要ないのは、コンパイラにより型推論されるからです。
これは書きやすいし読みやすい。

これが、ラムダ式の最も簡潔に書ける形です。

 

ただラムダ式でも、引数が複数ある場合は左辺に括弧が必要となります。また右辺が複数の文から成る場合はブラケット{...}が必要となります。

Func<int, int, int> sum = (a, b) => a + b;

Func<int, int, int> div = (a, b) => {a++; b++; return a / b;};

上はともかく、下はもはや簡潔とは言い難いでしょう。
(このプログラム自体には意味はないので一文で書けるじゃんってツッコミはナシで)

 

 

というわけで、ネタに困ったので放出したどうでもいい殴り書き記事でした!

  1. 2010年06月11日(金) 13時05分23秒|
  2. カテゴリ: C#|
  3. コメント:2

コメント

LINQ

こちらでははじめまして。
LINQ を使うといい感じです?いい感じです!

bool[][] Piyo(int max)
{
Func<int, int>[] ts =
{
n => n * (n + 1) / 2,
n => n * n,
n => n * (3 * n - 1) / 2,
n => n * (2 * n - 1),
n => n * (5 * n - 3) / 2,
n => n * (3 * n - 2)
};
return ts.Select(t =>
{
var r = Enumerable.Range(0, int.MaxValue).Select(t).TakeWhile(k => k < max);
return Enumerable.Range(0, max).Select(i => r.Contains(i)).ToArray();
}).ToArray();
}

元の問題読んでないので(ぉ、このコードが正しいかどうかは知りません。
  1. 2010/06/12(土) 00:33:46 |
  2. URL |
  3. bleis-tift #-
  4. [ 編集]

まあ普通はラムダ式が便利ですが

ラムダ式より匿名デリゲートのほうがいいかなという数少ない例外を。

1. System.Windows.Forms.Controlのinvoke()とかにメソッド参照を渡して何かやらせたいとき
まあやってみればわかりますがラムダ式だと括弧が1レベル余計にいります。
2. デリゲートの引数にrefとかoutとかついてるとラムダ式の型推論が対応してないのかお手上げになります。
  1. 2010/06/13(日) 01:59:11 |
  2. URL |
  3. jjsuwa #Ny8uzny.
  4. [ 編集]

コメントの投稿

管理者にだけ表示を許可する


画像の文字を半角数字で下記ボックスに記入ください。
文字が読みにくい場合はブラウザの更新をすると新しい文字列が表示されます。

プロフィール

xptn
Author:xptn
例外人生まっしぐらの高専卒大学生。平成生まれの21歳。
twitter

最近のエントリー

カテゴリー

最近のコメント

月別アーカイブ

リンク

RSSリンク

DTIブログ
ブログでアフィリエイト
DTIブログポータルへ
このブログを通報
Report Abuse