[C#]クエリ式

クエリ式というのを書いてみた。

語句

  • from
  • select
  • where
  • orderby
  • group
  • into
  • let
  • join
  • join into

語句

次に記述する語句は以下のデータを操作してるものとして記述している。

Ad

var persons = new []{
	new {name = "a",	Job = Job.archer,	HP = 1,	Luck = 1.3,	like = "cherry" },
	new {name = "a",	Job = Job.magician,	HP = 2,	Luck = 1.2,	like = "banana" },
	new {name = "b",	Job = Job.knight,	HP = 3,	Luck = 1.1,	like = "lemon" },
	new {name = "b",	Job = Job.axman,	HP = 1,	Luck = 1.3,	like = "peach" },
	new {name = "c",	Job = Job.magician,	HP = 2,	Luck = 1.2,	like = "orange" },
	new {name = "c",	Job = Job.witch,	HP = 3,	Luck = 1.1,	like = "orange" },
	new {name = "a",	Job = Job.witch,	HP = 2,	Luck = 1.6,	like = "apple" },
	new {name = "e",	Job = Job.magician,	HP = 5,	Luck = 1.1,	like = "lemon" },
	new {name = "d",	Job = Job.archer,	HP = 8,	Luck = 1.3,	like = "pine" },
};

Jobはenumで定義してるものとする。

public enum Job{ knight,magician,axman,archer,witch,swordman }

from

var data = from p in persons select p;

foreachの中に書く文を続ける様に、from の後に語句を連結することで、さらにフィルタリングしたり並べ替えたりできる。
定型句として先に記述するものとして理解。

select

var data = from p in persons select p;

抽出、並べ替え等のあとに最後に返す内容。

select p * p;

と書くと乗算したデータの羅列になる。

orderby

並べ替え用の語句。

var data = from p in persons
               orderby p.HP descending, p.Job
               select p;

HPで降順に並び替えをし、同数だった場合はJobで順位付けを行う、という内容。

where

フィルタリング。条件を記述することで以降の語句で記述する文の処理の対象から外す。

var groupByHP = from x in persons
                where x.Key >= 3
                select grouped;

group

グループ化する語句。

var groupByHP = from x in persons
                            group x by x.HP

これは、同じHPどうしで全員をグルーピングしたということ。

var groupByHP = from x in persons
                group x by x.HP
                into grouped
                where grouped.Key >= 3 // filter
                select grouped;

条件にあったグループだけ抽出したい場合はこう書く。
グループ条件はKeyに格納されるのでKeyが3以上、つまりHPが3以上になったグループだけを抽出したということ。

グループ化したオブジェクトは以下の様に取得できる。

    foreach (var a in groupByHP) {
        Console.WriteLine ("HP:"+a.Key +" persons are..");
        foreach (var b in a) {
                Console.WriteLine ("t"+b);
        }
    }
/*
HP:1 persons are..
	{ name = a, Job = archer, HP = 1, Luck = 1.3, like = cherry }
	{ name = b, Job = axman, HP = 1, Luck = 1.3, like = peach }
HP:2 persons are..
	{ name = a, Job = magician, HP = 2, Luck = 1.2, like = banana }
	{ name = c, Job = magician, HP = 2, Luck = 1.2, like = orange }
	{ name = a, Job = witch, HP = 2, Luck = 1.6, like = apple }
HP:3 persons are..
	{ name = b, Job = knight, HP = 3, Luck = 1.1, like = lemon }
	{ name = c, Job = witch, HP = 3, Luck = 1.1, like = orange }
HP:5 persons are..
	{ name = e, Job = magician, HP = 5, Luck = 1.1, like = lemon }
HP:8 persons are..
	{ name = d, Job = archer, HP = 8, Luck = 1.3, like = pine }
*/

into

直前までの条件であらたな識別子を持ったオブジェクトの集合を作成するための語句。

var groupByHP = from x in persons
                group x by x.HP
                into grouped
                where grouped.Key >= 3 // filter
                select grouped;

let

途中出力した内容を保持するための語句。
letで宣言するような使い方。
ここでデータを追加しておく。

var items = new []{
	new {name = "banana",	heal = 20},
	new {name = "apple",	heal = 32},
	new {name = "cherry",	heal = 53},
	new {name = "peach",	heal = 25},
	new {name = "pine",		heal = 89},
	new {name = "orange",	heal = 57},
	new {name = "lemon",	heal = 11},
};

letを使用した例はこちら。

Console.WriteLine ("nlist up liked == item.name:where");
var likePattern = 
	from man in persons
	from item in items
	where man.like == item.name
	let newName = man.name +"(" + man.Job.ToString() +")" + " with " + item.name
	let newHP = man.HP + item.heal * man.Luck
	select new {name = newName,HealedHP = newHP}
;

join

新たなオブジェクトを作成する。
join … on .. equals でセット。

例は、データを次のルールで加工する。

好きな果物を食べるとLuck係数分多く回復する。

where を使って上記のルールを達成した文。

var likePattern = 
	from man in persons
	from item in items
	where man.like == item.name
	let newName = man.name +"(" + man.Job.ToString() +")" + " with " + item.name
	let newHP = man.HP + item.heal * man.Luck
	select new {name = newName,HealedHP = newHP}
;

結果

{ name = a(archer) with cherry, HealedHP = 69.9 }
{ name = a(magician) with banana, HealedHP = 26 }
{ name = b(knight) with lemon, HealedHP = 15.1 }
{ name = b(axman) with peach, HealedHP = 33.5 }
{ name = c(magician) with orange, HealedHP = 70.4 }
{ name = c(witch) with orange, HealedHP = 65.7 }
{ name = a(witch) with apple, HealedHP = 53.2 }
{ name = e(magician) with lemon, HealedHP = 17.1 }
{ name = d(archer) with pine, HealedHP = 123.7 }

これを join で書くと以下の様になる。

var writeByJoin = 
	from man in persons
	join item in items on man.like equals item.name
	let newName = man.name +"(" + man.Job.ToString() +")" + " with " + item.name
	let newHP = man.HP + item.heal * man.Luck
	select new {name = newName,HealedHP = newHP}
;

出力される内容は全く同じ。

join into

入れ子になったオブジェクトを作成する。
into は先の説明でもあったとおり、新たに識別子をもったオブジェクトを作成する。

var fruiteLike = 
	from item in items
	join man in persons on item.name equals man.like into ps
	select new {name = item.name,persons = ps.Select( y => y.name + "(" + y.Job.ToString() + ")" )}
;

ソース

実際に書いてみた内容はこちら。->gist

プログラミングC# 第5版

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です