えムナウ Blog

えムナウ の なすがまま

目次

Blog 利用状況

ニュース


follow mnow at http://twitter.com


えムナウのプログラミングのページ

INETAJ

書庫

日記カテゴリ

ギャラリ

Linqはすごい? その4

Linqの各メソッドは foreach の連続で成り立っていることが今までで分かったと思います。

Linqはすごい? その2で見た、cal3はforeachが4個ということになり、cal2のforeachが1個より4倍以上時間がかかります。

Exceptionを出すコードとか、List<>のほうが便利な機能があるので一度List<>にしてみるとか、ある局面で使うには余分なオーバーヘッドもあります。

それを踏まえてLinqと付き合っていかなければいけないことになります。

 

さてLinqはすごいと信じ込まされているあなた以下のプログラムを見てください。

以下のLinq部分はメソッド何個(何回のforeach)になるでしょうか?

出力されるNoはどの順でしょうか? 

実際の出力ではなく 「10回(1,12,13,15,17)」 みたいにお答えください。

 

過去のシリーズ

Linqはすごい? その3

Linqはすごい? その2

Linqはすごい? その1

 

var al = new[] {

    new {Name="とっちゃん",Prefecture="1東京",No=13},

    new {Name="むたぐちさん",Prefecture="2大阪",No=17},

    new {Name="επιστημηさん",Prefecture="1東京",No=12},

    new {Name="中さん",Prefecture="2大阪",No=1},

    new {Name="えムナウ",Prefecture="1東京",No=15}

};

 

{

    var accounts = from a

                   in al

                   where a.No > 10

                   orderby a.No

                   descending

                   group a

                   by a.Prefecture

                   into accPref

                   orderby accPref.Key

                   select accPref;

 

    foreach (var accgroup in accounts)

        foreach (var account in accgroup)

            Console.WriteLine(account.No.ToString() + "," + account.Name + "(" + account.Prefecture + ")");

}

 

投稿日時 : 2008年1月25日 22:28

コメントを追加

# re: Linqはすごい? その4 2008/01/25 22:49 siokoshou

> その2で見た、cal3はforeachが4個ということになり、cal2のforeachが1個より4倍以上時間がかかります。
あ、なるほど!全然気にしてなかった(>_<)

>以下のLinq部分はメソッド何個(何回のforeach)になるでしょうか?
もうさっぱり…。内部でコレクションも作ってそう。
(15, 13, 12, 17)

# re: Linqはすごい? その4 2008/01/25 23:30 nsharp

出力順は 15, 13, 12, 17 だと思いますが、
foreachの回数については orderby の実装次第なので、.NETのソースを見てない漏れにはまったく見当がつきません。(´・ω・`)

ところで、今回の例はLINQを使わなければどれだけforeachの回数を減らせるものなのでしょう?

# re: Linqはすごい? その4 2008/01/26 8:31 えムナウ

>今回の例はLINQを使わなければどれだけforeachの回数を減らせるものなのでしょう?
基本表示側のforeachと同じです。
スピードと便利さのトレードオフですね。
否定的な情報を流していますが私自身はLinqを否定してはいません。

# re: Linqはすごい? その4 2008/01/26 11:16 nsharp

> 基本表示側のforeachと同じです。

うーん・・・、whereに関しては減らせるのはわかるのですが、orderbyやgroupbyに関してはどうなのでしょうか。(´・ω・`)

それと、その2で(意地の悪いタイミングでw)コメントを追加しましたが、
LINQでもforeachの回数を副作用(cal2)と同じにすることはできるんですよね。

そうなると、「トレードオフ」とはいいますが、結局LINQで本当に失ったものと得たものは何?という話になるわけでして・・・。

# re: Linqはすごい? その4 2008/01/27 0:06 えムナウ

つまり。
Linqという技術はforeachでできています。
foreachを多くしてもlinqでわかりやすさを重視する分ではいいんです。
そうでない局面では注意してくださいというわけです。

# re: Linqはすごい? その4 2008/01/27 1:34 nsharp@粘着モード

これまでの反論をまとめますよ。(`・ω・´)

その1: どちらが簡単で分かりやすくてなおかつ速いのでしょうか?

 ・簡単さ(= 短さ) → クエリー構文ではなくてメソッドベースにすれば非LINQよりも短くできる
 ・分かりやすさ → 主観なのでパスw
 ・速さ → 目立った差がつかないのはえムナウさんご自身でご指摘済み

その2: どの順序で速いと思いますか?

 ・LINQでもforeachの回数を cal2 と同等にできるのを(卑怯な後出しでw)指摘済み

その3: cal2 と cal3 + Extensionクラス のどちらを書きますか?

 ・車輪の再発明とコードのバグ(maxとminの初期値がおかしい)により、やっぱり標準クエリ演算子に身をまかせるべき

その4: Linq部分はメソッド何個(何回のforeach)になるでしょうか?

 ・非LINQにしたところで、foreachの回数はせいぜい数回(whereぐらい)しか削減できない
 ・非LINQでorderby、groupbyをどう実現するつもりなのか

にもかかわらず、「LINQってほんとにすごいの?」という疑念はペンディングのままなのは、どういう意図なのでしょうか。

それと、できれば各スレで投げかけた疑問点は回答をきちんと明示していただければと思います。

> foreachを多くしてもlinqでわかりやすさを重視する分ではいいんです。

LINQのメリットは、クエリーの結合能力(composability)と、並列による高速化への余地(free lunch)があることだと思います。
長い目で見た場合、これらは宣言性によるわかりやすさよりも重要だと思います。

# re: Linqはすごい? その4 2008/01/27 9:09 えムナウ

>それと、できれば各スレで投げかけた疑問点は回答をきちんと明示していただければと思います。
昨日はわんくま勉強会の為に回答できませんでした。
すみません。

では今までの解説をします。
その1では私がLinqの説明時にいつも使っているクエリをforeachで書きなおしてみました。
おそらく皆さんも今まで書いていたんであろうコードです。
これによってlinqというのはforeachの置き換えだよって気づいてほしかったのです。

その2ではそれ(linqというのはforeachの置き換え)を強調するためにあえて速度比較をしてみました。
その結果ですが多くの方は4倍以上違うのが当たり前のコードをすんなりと受け入れてしまいました。

その3ではマイクロソフトのExtensionに似せたコードを作成して4倍以上違う根拠を見せようとしました。
あんまり似ていたので「コード出すのやばいんじゃ」って意見もありましたがあくまで挙動を調べた私のオリジナルです。
コードのバグ(初期値がおかしい)とありますが実行して実証されたのでしょうか?

つまり、一貫してこのシリーズで言いたかったことは「linqというのはforeachの置き換えの技術である」という見過ごされがちな一面です。

その4ではじゃ、どんなふうに置き換わっているのって話です。
nsharpさんの意見に「クエリー構文ではなくてメソッドベースにすれば非LINQよりも短くできる 」ってありますが、そのnsharpさん自身が今回はどんなメソッドに展開されるか「まったく見当がつきません。」と書いていられます。
もちろんMSDNにはメソッドにどんなものがありかも公開されています。
http://msdn2.microsoft.com/ja-jp/library/19e6zeyy.aspx

>「LINQってほんとにすごいの?」という疑念はペンディングのまま
Linqの各メソッドは foreach の連続で成り立っている、使い方によっては今まで自分でforeachを書いていた時より何倍も時間がかかることを気づかずに書いてしまうこともありうる、それを踏まえてLinqと付き合っていかなければいけない、と結論付けているつもりですが、ペンディングにしてはいないつもりです。

# re: Linqはすごい? その4 2008/01/27 11:49 えムナウ

>orderbyやgroupbyに関してはどうなのでしょうか。
結果を格納するListを作ったとします。
たとえばStackのようにFILOにすればorderbyのdescending、FIFOにすれば通常になります。
groupbyは結果Listを検索してdictionaryで入れることになりますね。

# re: Linqはすごい? その4 2008/01/27 12:51 nsharp

解説ありがとうございます。
コメントとして埋もれてしまうのはちょっともったいない内容ですね・・・。(´・ω・`)

> コードのバグ(初期値がおかしい)とありますが実行して実証されたのでしょうか?

その3は実行してませんでした。

ので、実行しようとしたら、・・・コンパイルエラーでした。(例外をスローする部分が)

いや、それは置いといて、w
ExMaxとExMinの挙動は正しかったです。バグではありませんでした。

大変失礼いたしました・・・。

> nsharpさんの意見に「クエリー構文ではなくてメソッドベースにすれば非LINQよりも短くできる 」ってありますが、

その1の単純な例(whereとselectのみ)での話です。

> そのnsharpさん自身が今回はどんなメソッドに展開されるか「まったく見当がつきません。」と書いていられます。

えーと、見当がつかないと言ったのは、どういうメソッドに展開されるかという話ではなくて、
orderbyやgroupbyのメソッドの実装内容が見当がつかないということです。

IOrderedEnumerableやIGrouping・ILookupみたいに、イテレータの再作成が伴うものでは、
実装次第で効率がぜんぜん違って、foreachの回数も変わってくるからです。

槍玉に挙げるのは申し訳ないのですが、たとえばこのプロジェクトのOrderBy/ThenByなんかはあまり効率がよろしくない例です。
ttp://www.codeplex.com/LINQSQO/

> つまり、一貫してこのシリーズで言いたかったことは「linqというのはforeachの置き換えの技術である」という見過ごされがちな一面です。

これはLINQとどれだけ長く付き合って来たかによるのですが、

 1. foreach + func : IEnumerable<T> -> (T -> U) -> IEnumerable<U>
 2. yield return : T -> IEnumerable<T>
 3. nested foreach + func : IEnumerable<T> -> (T -> IEnumerable<U>) -> IEnumerable<U>

で、1 → functor、2 → unit、3 → bindとみなせ、LINQは「Monad in disguise」であることは過去数年にわたって言われてきたことです。
見過ごされがちな一面なのかは正直わかりません・・・。(´・ω・`)

# re: Linqはすごい? その4 2008/01/27 13:43 えムナウ

>コンパイルエラーでした。(例外をスローする部分が)
using漏れじゃないですか?
コードは一番最初と比べては例外のところ書きなおしています。

>orderbyやgroupbyのメソッドの実装内容が見当がつかないということです。
>実装次第で効率がぜんぜん違って、foreachの回数も変わってくるからです。
なるほど。

>1 → functor、2 → unit、3 → bind
>LINQは「Monad in disguise」
あまり海外のサイトは見ないので(MS技術系を少しだけ)私が知らなかっただけなのかもしれません。

>過去数年にわたって言われてきたことです。
>見過ごされがちな一面なのかは正直わかりません・・・。
その割に cal2 と cal3 速度比較にびっくりされている人も多いようです。
見過ごされてないならすぐにわかるはずだと思うんですけどね。

# re: Linqはすごい? その4 2008/01/27 13:56 nsharp

コンパイルエラーの件:

> if (source == null) throw ArgumentNullException("source");

throw の後に「new」が必要というだけです。
論点には影響しないので、あまり気になさらないでください。w

# re: Linqはすごい? その4 2008/01/27 14:06 えムナウ

>throw の後に「new」が必要というだけです。
あ、修正ミスでしたね。
テストバージョンから書き写すしたあと手で修正した部分のミスです。

# agnUVuKAGSLdTbA 2022/04/19 12:23 johnansaz

http://imrdsoacha.gov.co/silvitra-120mg-qrms

タイトル
名前
URL
コメント