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