- 締切済み
C#についての質問(主にLinq関係)
ずっと独学でプログラミングをやっている者です。 C#を用いて現在開発しているのですが、たまたま見つけたLinq構文がとても綺麗だと思い、 現在練習中です。 そこで少し疑問点が出てきたので誰か回答お願いします>< 例えば、「ある整数の配列の中から、偶数を探し出し、見つかった要素の数字を見つかった要素の個数分加算する」というような問題があったとします(一例ですが...)。 普通に書くと...(ちょっと上下に切り詰めてます><) int[] ary = new int[]{2, 1, 5, 4, 5, 2}; //<<<今後この行は割愛します^^ int count = 0; for(int i = 0; i < ary.Length; i++) if(ary[i] % 2 == 0) count++; for(int i = 0; i < ary.Length; i++) if(ary[i] % 2 == 0) ary[i] += count; //結果は{5, 1, 5, 7, 5, 5} みたいな感じでしょうか。 これでも全然いいのですが、条件を二回使用しているのもなんだかすっきりしないですし、 IEnumerableなコレクション全てに対応させるには少し不向きな書き方ですよね? forEachも考えましたが、forEachだと最後の行が... forEach(int i in ary.slect(new {val = ary[i], ix = i}) if(i.val % 2 == 0) ary[i.ix] += count; みたいな回りくどい方法しか今のところ思いつきません。 理想は... var where = ary.where(v => (v % 2 == 0)); int count = where.count(); Array.ConvertAll(where, v => v + count); //<<<もちろんコンパイルエラー^^ こんな感じでかけたらいいのになぁとか思ってます。 最後の行を... ary = ary.select(v => v + count).ToArray(); とすれば似たようなことはできるのですが、 これだと新しい配列が出来てしまいますよね? 今回の例では構わないのかもしれませんが、 大きな配列になってくるとメモリが心配になる書き方なので少し気持ち悪いです>< それとも現代ではそんなことはお構いなしなのかなぁ...とか思うときもありますが^^ (↑なんせ独学なもので常識知らずです><) なにかすっきりとした実装方法は無いでしょうか? それとも今回のような配列の中身を更新、変換するような場合には、 Linqを用いること自体が推奨されていないのでしょうか? ずっと、C++と同じような方法でコレクションを扱ってきていたので、 ガベージコレクションの挙動も良くわかっていません。 deleteのし忘れを防ぐぐらいの機能なのか、配列だろうがどんどん新しくメモリを確保しても 大丈夫な機能なのか...?です。 Linqのような構文もまだまだ付け焼刃です。 もしかしたら、結構基本的な所を見落としている可能性もあります>< どなたかご教授お願いしますm(-_-)m
- みんなの回答 (1)
- 専門家の回答
みんなの回答
- catpow
- ベストアンサー率24% (620/2527)
ストレートな回答ではありませんが・・・ >>最後の行を... ary = ary.select(v => v + count).ToArray(); とすれば似たようなことはできるのですが、 これだと新しい配列が出来てしまいますよね? IEnumerableは、Read Only、書き換え不可として扱われますので、更新処理が入るなら、結界をいれる新しい変数が必要になりますね。 >>大きな配列になってくるとメモリが心配になる書き方なので少し気持ち悪いです>< LinqでIEnumerableな変数を扱うと、ちょっと不思議な「遅延実行」ってことをやってくれます。 つまり、処理の途中で計算処理結果を新しいIEnumerableな変数を作って、そこに代入すると、例えば100万個のデータがあれば、それらの追加メモリと処理時間が必要になる気がします。 でも、実際には、そうならないんですね。 計算結果を表示する等、結果を実際に使うときになって、必要なデータだけ、計算処理を行ってくれる。 だから、メモリのことは気にしないで、新しいIEnumerableな変数を作ってもいいんです。 これは、単なる計算だけじゃあなく、データベースへのSELECT処理でも同じです。だから、100万件のデータから条件に合うデータをSELECTで抽出する処理を書いても、結果を使わないならDBへのアクセスをしないという、トリッキーなことをやってくれるそうです。 もちろん、従来どおり、配列を使って処理すると、こんなメリットは無いので、大量データの処理をするなら、IEnumerableを使ったほうがいいですね。 .NET クラスライブラリも配列より、列挙オブジェクトを使うように変化しているそうです。
お礼
IEnumerableにはそんな隠れ仕様があったんですね^^ c++時代の癖なのか、何かインスタンスを作る度にメモリを気にしていました。 サンプルを見るたびになんでこんなにメモリを使う書き方をするのだろうと思っていましたが一つ謎が解けました。 これから積極的に使っていきます^^ 有難うございました。