LoginSignup
3
2

More than 5 years have passed since last update.

LINQつかいはじめました

Last updated at Posted at 2018-12-02

いまさらですが LINQつかいはじめました
LINQ式は前々から覚えようと思いつつ、分量も少ないので 必要になるまで遅延評価していましたが
そろそろ必要になったので 勉強しました
トータルでも1日かからず 完全に理解しました

rikai.jpg

お題

2次元配列からなる整数の配列が与えられる
{ 1,2,3 },{ 1,4,5 },{ 1,2,6 };
この中から 3より大きい要素のみ取得する
ただし 配列の形状は崩さず 空集合もみとめない
つまり 下記の結果が得られる
{4, 5},{6}

勉強&回答

クエリ形式の練習

SQLっぽい構文がある。
なぜクエリ構文だと 最後にSelectかGroupByがないとNGかは よくわからない

int[] a_ = { 2, 7, 5, 8, 1, 6 };

// 本当は var o1 = ... と書くが 勉強のため型を書く
IEnumerable<int> o1 =
    from a in a_
    where a > 5
    orderby a descending
    select a;                       // クエリ形式だと select句必要


// 結果
{8,7,6}

メソッドチェーン

一般的にはこちらの形式が好まれるのでこちらに統一する
SelectなくてもOK

IEnumerable<int> o2 =
    a_                              // from a in a_
    .Where(x => x > 5)              // where a > 5
    .OrderByDescending(x => x)      //orderby a descending
    ;                               //select a;


// 結果
{8,7,6}

ForEach

ForEachを使えば 全ての要素に対して処理を行える
(LINQ式ではないが メソッドチェーンなので LINQ以外も繋げられる)

a_
    .Where(x => x > 5)
    .OrderByDescending(x => x)
    .ToList()
    .ForEach(x => Console.Write(x));


// 結果
876

Selectは誤り

上記をLINQのSelect()を使えば出来そうだが 何も出力されない
Selectの戻りを何か工夫すればいけるんだろうか?
ここはよく理解できてない
(多分Selectの戻りが IEnumerableだからだとおもうが深く追わない)

a_
.Where(x => x > 5)
    .OrderByDescending(x => x)
    .Select(x => { Console.Write(x); return 1; });

Selectで射影し要素の値を2倍値にする

a_
.Where(x => x > 5)
    .OrderByDescending(x => x)
    .Select(x => x * 2)
    .ToList()
    .ForEach(x => Console.Write("{0}, ", x));

//結果
{16, 14, 12}

Anyをつかい 配列に2が含まれるかどうか

a_.Any(x => x == 2);


//結果
True

Anyを使い 2を含む配列のみ取得

int[][] a2_;
a2_ = new int[3][];
a2_[0] = new int[]{ 1,2,3 };
a2_[1] = new int[]{ 1,4,5 };
a2_[2] = new int[]{ 1,2,6 };

a2_
.Where(x => 
    x.Any(y => y == 2)  
)


//結果
{1, 2, 3}
{1, 2, 6}

y>3を含む配列取得

IEnumerable<int[]> o3 = 
a2_
.Where(x =>
    x.Any(y => y > 3)
);


//結果
{1, 4, 5}
{1, 2, 6}

SelectManyは多次元配列を1次元に投影する

IEnumerable<int> o4 =
    a2_
        .SelectMany(x => x
            .Where(y => y > 3
    ));


//結果
{4, 5, 6}

Selectは配列構造維持したまま射影できる

IEnumerable<int[]> o5 =
a2_
    .Select(x => x
        .Where(y => y > 3)
        .ToArray()
    )
;


//結果
{}
{4, 5}
{6}

まだ空集合が入ってる

空集合を除去

IEnumerable<int[]> o6 =
a2_
    .Select(x => x
        .Where(y => y > 3)
        .ToArray()
    )
    .Where(x => x.Count() > 0)
;


//結果
{4, 5}
{6}

望み通りのデータが出来た!!

パフォーマンスのためAnyを使う&int[][]に

IEnumerable<int[]> o6 =
a2_
    .Select(x => x
        .Where(y => y > 3)
        .ToArray()
    )
    .Where(x => x.Any())
    .ToArray()
;


//結果
{4, 5}
{6}

総括

ToArrayが入ってしまうので速度的に気になるのだけど
foreachで書くことを考えると
とてもシンプルに出来たと思う

LINQは正義!

3
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2