• 締切済み

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

  • CSS
  • 回答数1
  • ありがとう数1

みんなの回答

  • catpow
  • ベストアンサー率24% (620/2527)
回答No.1

ストレートな回答ではありませんが・・・ >>最後の行を... ary = ary.select(v => v + count).ToArray(); とすれば似たようなことはできるのですが、 これだと新しい配列が出来てしまいますよね? IEnumerableは、Read Only、書き換え不可として扱われますので、更新処理が入るなら、結界をいれる新しい変数が必要になりますね。 >>大きな配列になってくるとメモリが心配になる書き方なので少し気持ち悪いです>< LinqでIEnumerableな変数を扱うと、ちょっと不思議な「遅延実行」ってことをやってくれます。 つまり、処理の途中で計算処理結果を新しいIEnumerableな変数を作って、そこに代入すると、例えば100万個のデータがあれば、それらの追加メモリと処理時間が必要になる気がします。 でも、実際には、そうならないんですね。 計算結果を表示する等、結果を実際に使うときになって、必要なデータだけ、計算処理を行ってくれる。 だから、メモリのことは気にしないで、新しいIEnumerableな変数を作ってもいいんです。 これは、単なる計算だけじゃあなく、データベースへのSELECT処理でも同じです。だから、100万件のデータから条件に合うデータをSELECTで抽出する処理を書いても、結果を使わないならDBへのアクセスをしないという、トリッキーなことをやってくれるそうです。 もちろん、従来どおり、配列を使って処理すると、こんなメリットは無いので、大量データの処理をするなら、IEnumerableを使ったほうがいいですね。 .NET クラスライブラリも配列より、列挙オブジェクトを使うように変化しているそうです。

hira_kazu
質問者

お礼

 IEnumerableにはそんな隠れ仕様があったんですね^^  c++時代の癖なのか、何かインスタンスを作る度にメモリを気にしていました。 サンプルを見るたびになんでこんなにメモリを使う書き方をするのだろうと思っていましたが一つ謎が解けました。  これから積極的に使っていきます^^  有難うございました。

関連するQ&A

  • C言語の配列の入れ方について質問です。

    下記のプログラムで1234という連続した数字を入れたら配列val[0]~[3]に val[0] = 1 val[1] = 2 val[2] = 3 val[3] = 4 というように入れたいのですが、どのようにして別々にすれば良いですか?宜しくお願いします。 #include<stdio.h> int main(void) { int num[10]; int val[4]; int i; printf("式:"); scanf("%d",num); for(i=0;i<4;i++){ val[i] = 0; } for(i=0; i<4; i++){ if((num[i] >= 1) && (num[i] <= 9)){ /*1から9の数値が入ったならば*/ val[i] = num[i]; } } for(i=0; i<4; i++){ printf("答え%d:%d\n",i,val[i]); } }

  • C言語 ポインタ 関数

    キーボードから文字列”abcdefg”を入力し、main関数で配列aryに格納する。 main関数から配列aryの先頭アドレスを副関数に引き渡す。 副関数で配列aryの最後尾の要素の内容を';'に変更する。 main関数で配列aryの内容を表示する。 この問題が解けません... #include <stdio.h> int main (void) { char ary[]="abcdef"; int *p; int i,x; p=&ary[0]; func(&i); for (x=0;x<=7;x++){ printf("%s",ary[x]); void func (int i) if(i==\0) i=';' else i++ } return 0 } とりあえずこんな感じなんですけど、出来ませんでした...

  • C言語

    3. 整数配列data の,data[left]からdata[right-1]の最小値がある添字番号を返す関数 int min_ind_ary(const int data[ ], int left, int right) で最小値が複数あるときは,一番小さい添字を返すようにするにはどうしたらよいのかわかりません? 途中経過↓ #include <stdio.h> int min_ind_ary(const int data[10],int left,int right) { int i,min = 0; for( i = 1; i < left; i++){ if(data[min] < data[i]) min = i; } return min; } void print_ary(const int data[10], int size){ int i; for(i = 0; i < 10; i++){ printf("%2d", data[i]); } } void sort_ary (int data[10], int size) { int i; for(i = 0; i < size - 1; i ++ ) { int min, work; min = min_ind_ary(data, i, size); work = data[min]; data[min] = data[i]; data[i] = work; } return; } int main(void) { int data[10] = {1, 6, 4, 8, 2, 3, 5, 9, 7, 4}; print_ary(data, 10); sort_ary(data, 10); print_ary(data, 10); return 0; }

  • C言語のプログラミングについて質問です。

    以下の文を出力して入力:に16進数を入れると10進数に変換した数値の小さい列順に並ぶプログラムを作りたいのですがうまく出来ません。 仕様は以下に記載します。 入力:__、__、__、__、__EnterKeyで結果を表示。 以下のバブルソートの文のどこをいじれば良いでしょうか? 返答宜しくお願いします。 #include <stdio.h> int main (void) { char data[256]; int val[100]; int i = 0; int work; int j; int k; printf("入力 = "); scanf("%s",data); for(i=0;i<100;i++){ val[i] = 0; } k=0; for(i = 0;i<100 ; i++){ if(data[i] == 0x00){ //data[i]がNULLだったら処理を抜ける k++; break; //enterキーでprintf出力 } else if(data[i] == ','){ //カンマだったら /*printf("%d\n",k);*/ k++; } else{ if(data[i] >= 'A' && data[i] <= 'Z'){ //data[i]にAからZが入ったら val[k] = val[k] *16 + data[i] -'A'+10; } else if(data[i] >= '0' && data[i] <= '9'){ //data[i]に0から9が入ったら val[k] = val[k] *16 + data[i] -'0'; } } } /* printf("k=%d\n",k); for(i=0;i<k;i++){ printf("出力 = %d\n",val[i]); } */ //バブルソート//     for(i=0; i<k-1; i++) { if(val[i] < val[i+1]) { } else{ work = val[i]; val[i] = val[i+1]; val[i+1] = work; } } for(i=0;i<k;i++) { printf("出力 = %d\n",val[i]); } }

  • 「シンボルを見つけれません」というエラーへの対処法

    下記のコードの If(type.compareTo("名詞") == 0); で「シンボルを見つけれません」「シンボル:メソッドif(boolean)」というエラーが出てしまいます。 なぜ、他のif文ではエラーが出ないのにこの行ではエラーが出るのか分かりません。 対処法を教えていただけないでしょうか? public void set_dictionary(String dict_filename) { } public int run(byte[] text, int start, int length, byte[] terms) { String type; //品詞の比較用 byte[] buf1 = new byte[1000]; //textの内容を一時的に格納しておくための配列1 byte[] buf2 = new byte[1000]; //textの内容を一時的に格納しておくための配列2 int i, j, k, count1, count2, FLG; count1 = 0; count2 = 0; k = 0; FLG = 0; for(i = start; i < length; i++) { if(text[i] == '\t') { FLG = 1; count2 = 0; } else if(text[i] == ' ') { FLG = 0; count1 = 0; } else { if(FLG == 1) { buf2[count2++] = text[i]; } else if(FLG == 0) { buf1[count1++] = text[i]; } } if((count2 == 5)&&(FLG == 1)) { type = new String(buf2, 0, 4); If(type.compareTo("名詞") == 0); { for(j = 0; j < count1; j++) { terms[k++] = buf1[j]; } terms[k++] = '/'; } count2 = 0; FLG = 2; } } return k; //term中のデータの長さを返す }

  • C#についてです

    複数のグラフを作成しようと思い、2つのクラスを作りました。 1つ目のクラスで、下のように書き、 public class clsWave { public const int count = 1024; public int[] data = new int[count];     public byte range; public double[] realValue = new double[count]; public PictureBox pcb;     public Pen myPen; ; public void Draw(Graphics g, int v) { int h = pcb.Height; int w = pcb.Width; int stpW = w / count; // X座標       Point[] lp = new Point[count]; for (int i = 0; i < data.Length; i++) { lp[i] = new Point(i * stpW, h - (int)(realValue[i] / (v * 8) * h)); } g.DrawLines(myPen, lp); } } もう一つのクラスで、グラフを下のように作りました。      clsWave BI = new clsWave(); clsWave BV = new clsWave(); clsWave CI = new clsWave(); clsWave CV = new clsWave(); clsWave EI = new clsWave(); clsWave EV = new clsWave(); clsWave SI = new clsWave(); clsWave SV = new clsWave(); この、グラフを配列にしたいのですが、私の力では、まだわかりません。 どのように作ればよいのでしょうか?教えてください。よろしくお願いいたします。

  • C言語を使って、ファイルの読み込みをして切り出して2次元配列に格納した

    C言語を使って、ファイルの読み込みをして切り出して2次元配列に格納したいのです。 1,2行目に配列の行の数と列の数が書かれ、3行目から改行とカンマ、スペースで区切られて配列が書かれているテキストを読み込んで2次元配列に格納する。 テキストの例) 4 3 1.1 1.2 1.3 1.4 1.5 2.1 2.2 2.3 2.4 2.5 3.1 3.2 3.3 4.4 3.5 というプログラムを書いています。色々と参考書やサイトを参考してとりあえずの形にはなったと思ったのですが、実行してもエラーが出ます。 どこまで動いているか調べたところ、一行ごとに読み出してそれを切り出して行くところでおかしな事をしてしまっているようですが、どう変えたらいいものか分かりません。 なので、その点のアドバイスと 大きさの分からないファイルから1,2行目を読み出すのはこれで変な動きをする恐れはないか の2点についてヒントでも構わないので、教えてください。 以下、書いたソースです(申し訳ないのですが、文字数の関係で一部省略しています。) #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[] ) { double ** mainhairetu; int size_x, size_y; /* size_x 行 size_y 列 */ int i,j,count=0,count2; int *cut,*temp2; double temp; char s2[] = " ,"; char gyou[10],*num; FILE *fil; while((fgets(gyou,10,fil)) !=NULL){ if(count == 0){ size_x=atoi(gyou); count++; }else if(count ==1){ size_y=atoi(gyou); count=count+1; }else{ break; } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ここでmallocを使ってcutとmainhairetuの2つの配列を作っています。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ count=0; for (i = 0; i < size_y+2; i++) { mainhairetu[i][0] = atof( strtok( fgets(cut,50,fil),s2 ) ); for (j = 1; j < size_x; j++){ if(count <=1){ count++; break; }else{ mainhairetu[i][j] = atof( strtok( NULL,s2 ) ); } } } for(i=0;i<size_y;i++){ for(j=0;j<size_y;j++){ printf("%f",mainhairetu[i][j]); } printf("\n"); } return(0); }

  • 配列のX件目~Y件目を全件ループ以外に取得できますか?

    配列のX件目~Y件目を取得するもっと良い方法がもしあれば教えていただきたいです。 今のところ以下で考えています。 <?php $array = Array(1,2,3,4,5); $count = 0;$x = 3;$y = 5; foreach($array as $key >= $val){ if($count >= $x && $count <= $y) $new_array[] = $val; $count++; } ?>

    • ベストアンサー
    • PHP
  • コンパイル時の静的チェックについて

    次のような配列があります。 static const int ary[]={1,2,3,4,5}; この配列の要素数が5であることは、次の方法でコンパイル時にチェック出来ます。 #define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) static_assert(ARRAYSIZE(ary) == 5); では、この配列で4以上の要素数が2であることをコンパイル時にチェックするにはどうしますか? 実行時であれば次のように出来ます。 assert(count_if(ary, ary+sizeof(ary), [](int i)->bool {return (i >= 4); }) == 2); 結果はコンパイル時に確定しているはずなのですが、この方法だとライブラリ関数を使用するので実行時にしかチェック出来ません。 「テスト用プロジェクトを作って...」というのも「コンパイル時に確認」ではないので無しとします。

  • ソート

    お世話になります。配列のソートなのですが、どうも思い通りの結果になりません。 配列の中から最大値と最小値を探し、最小値を配列0に、最大値を配列の最後に移動します。その2つ以外の数字の順番は変えません。 例) {4,3,2,0,1,2} 最小値は0、最大値は4なので→{0,3,2,1,2,4} {4,3,2,1} → {1,3,2,4} {1,3,2,4,} → {1,3,2,4} 流れとしては、まず最小値を求め配列0に移動させ、次に最大値を求め配列の最後に移動させようと思います。 プログラムは以下のように組みました。 public int[] sortOfSort(int[] array) { int count_min = 0; int min = array[0]; for (int i = 0; i < array.length-1; i++) { // 最小値を求める if (min > array[i + 1]) { min = array[i + 1]; count_min++; // 最小値の配列のインデックスを確保 } } for (int k = count_min; k > 0; k--) { // 最小値の移動 int temp_min = array[k - 1]; array[k - 1] = array[k]; array[k] = temp_min; } int count_max = 0; int max = array[0]; for (int j = 0; j < array.length-1; j++) { // 最大値を求める if (max < array[j + 1]) { max = array[j + 1]; count_max++; // 最大値の配列のインデックスを確保 } } for (int l = count_max; l < array.length-1; l++) { //最大値の移動 int temp_max = array[l + 1]; array[l + 1] = array[l]; array[l] = temp_max; } return array; } 間違っているところがわかりましたら宜しくお願いします。

    • ベストアンサー
    • Java