LINQ.Enumerable
目次
概要
System.Linq.Enumerableクラス
・IEnumerableインターフェイスを継承している。
・拡張メソッドSumを始め、様々なメソッドを定義している。
※拡張メソッドについては「オブジェクト指向: 特殊なクラス/拡張メソッド」を参照。
public static class System.Linq.Enumerable
{
public static int Sum(this IEnumerable<int> source);
}
拡張メソッドの定義の結果、ary.Sum() が可能
※aryはIEnumerable<int>型の変数
IEnumerable<int>型の変数を宣言するには、
var
を用いる。
なお、IEnumerableインターフェイスを継承したオブジェクトの操作は、
LINQ to Objectに分類される。
・LINQ to SQL (データベースオブジェクト:Entity Frameworkに対する操作)
・LINQ to XML
IEnumerableインターフェイス拡張メソッド
var people = new[]{
new { Name="一郎", Height=160, Weight=50 },
new { Name="二郎", Height=170, Weight=60 },
new { Name="三郎", Height=180, Weight=70 }
};
var WeightSum = people.Sum(person => person.Weight);
// ⇒ Weightsum : 180
数
int[] numbers = new int[] { 0, 1, 2, 3, 4, 5 };
int count = numbers.Count();
// count : 6
最大値
int max = numbers.Max();
// max : 5
//最大の(身長-体重)を求める。
var judgeValue = people.Max(person => person.Height – person.Weight);
// judgeValue : 110
最小値
int min = numbers.Min();
// min : 0
平均値
double avr = numbers.Average();
// avr : 2.5
逐次処理
each・foreach
foreach(var i in ary)
{
Console.WriteLine(i);
⇒ 0 1 2 3 4 5
}
抽出
写像(map・select)
var map = ary.Select(elm => elm * 2);
OfType
foreach (var elm in myObj.Select(n => n is string)) Console.Write(elm);
foreach (var elm in myObj.OfType<string>()) Console.Write(elm);
var list = new List<string>();
list.AddRange(myObj.OfType<string>());
フィルター(filter・where)
var map = ary.Where(elm => elm == 2);
差分・共通項・重複削除
var allAry = Enumerable.Range(start: 1, count: 10);
int[] exceptAry = { 3, 7 };
var newAry = allAry.Except(second: exceptAry).ToArray();
差分を取得
newAry:1 2 4 5 6 8 9 10
Intersect
int[] ary1 = { 1, 3, 4, 5, 7, 9 };
int[] ary2 = { 2, 3, 5, 6, 9 };
var newAry = ary1.Intersect(second: ary2).ToArray();
共通値を取得
newAry:3 5 9
Union
int[] ary1 = { 1, 2, 3, 3 };
int[] ary2 = { 2, 3, 4, 4 };
var newAry = ary1.Union(second: ary2).OrderBy(_ => _).ToArray();
→1, 2, 3, 4
※重複も削除される
Distinct
int[] ary = { 0, 1, 1, 2, 3, 3, 4, 5, 5 };
var distinct = ary.Distinct();
拡張子の重複を削除して抽出
⇒ distinct : 0 1 2 3 4 5
string[] oldAry = { "a.txt", "b.txt", "c.jpg", "d.doc", "e.txt" };
string[] newAry = oldAry.Select(x => Path.GetExtension(x)).Distinct().ToArray();
newAry:txt jpg doc
指定の要素
var rnd = new Random(Seed: 0);
var ary = Enumerable.Repeat(element: 0, count: 10000).Select(_ => rnd.Next());
var target1 = ary.ElementAt(index: 4649);
var target2 = ary.ElementAtOrDefault(index: 4649);
Take/Skip
int[] ary = { 1, 2, 3, 4, 5 };
ary = ary.Take(3).Concat(new int[] { 0 }).Concat(ary.Skip(3)).ToArray();
→1, 2, 3, 0, 4, 5
SkipWhile/TakeWhile
int[] myInt = Enumerable.Range(start: 1, count: 100).ToArray();
var ary = myInt.SkipWhile(n => n < 10).TakeWhile(n => n < 21);
ary:10~20
int sum = 0;
foreach (var n in Enumerable.Range(1, int.MaxValue).TakeWhile(c => sum < 100))
{
sum += 1;
Console.WriteLine(sum);
}
条件が成立する間は実行
First
※対象が無い場合:例外発生
FirstOrDefault
※対象が無い場合:型のデフォルト値(0,null等)
Last
※対象が無い場合:例外発生
LastOrDefault
※対象が無い場合:型のデフォルト値(0,null等)
int?[] ary = { 0, 1, 2 };
var my1st = ary.First(n => n < 2);
var my1st = ary.FirstOrDefault(n => n < 2);
var my1st = ary.Last(n => n < 2);
var my1st = ary.LastOrDefault(n => n < 2);
int?[] ary = { 0, 1, 2 };
var my1st = ary.FirstOrDefault(n => n > 2) ?? -1;
→Null → -1
Single / SingleOrDefault
int[] ary1 = { 2 };
int[] ary2 = { };
int[] ary3 = { 2, 3 };
int sglValue1 = ary1.Single();
→2
int sglValue2 = ary2.Single();
→実行時例外
int sglValue2 = ary2.SingleOrDefault();
→0
int sglValue3 = ary3.SingleOrDefault();
→実行時例外
DefaultIfEmpty
string[] ary = { };
foreach (var elm in ary.DefaultIfEmpty(defaultValue: @"ありません。")) Console.WriteLine(elm);
要素数:0 の場合の値を指定(同型の値のみ)
キャスト
string[] str = obj.Cast<string>().ToArray();
int[] myInt = { 1, 2, 3 };
long[] myLong = myInt.Cast<long>().ToArray();
→エラー:Castは参照型にしか使用できない
long[] myLong = myInt.Select(n => (long)n).ToArray();
順序
並び替え(sort)
var orderBy = people.OrderBy(person => person.Height);
OrderByDecending
var orderByDec = people.OrderByDescending(person => person.Height);
DateTime[] ary = new DateTime[]
{
new DateTime(year: 2010, month: 1, day: 1),
new DateTime(year: 2001, month: 1, day: 1),
new DateTime(year: 2005, month: 1, day: 1),
new DateTime(year: 2003, month: 1, day: 1)
};
var newary1 = ary.OrderBy(n => n);
=Array.Sort(ary, (x, y) => Math.Sign(x.Ticks – y.Ticks));
ThenBy
var ThenBy = people.OrderBy(person => person.Height).ThenBy(person => person.Weight);
ThenByDecending
var ThenByDec = people.OrderBy(person => person.Height).ThenByDescending(person => person.Weight);
Sort
var list = new List<DateTime>() {
DateTime.Now, DateTime.MinValue, DateTime.MaxValue };
list.Sort((x, y) => Math.Sign(x.Ticks – y.Ticks));
list.ForEach( c => Console.WriteLine(c) );
反転
// ⇒ 5 4 3 2 1 0
判定
ALL・ANY
bool judge = ary.All( elm => elm > 3);
全ての要素が条件を満たすか否か?
bool judge = ary.Any( elm => elm > 3);
どれか1つの要素が条件を満たすか否か?
int[] ary1 = { 1, 3, 4, 5, 7, 9 };
int[] ary2 = { 2, 3, 5, 6, 9 };
int[] ary3 = { 1, 3, 4, 5, 7, 9 };
bool judge2 = ary1.SequenceEqual(second: ary2);
judge2:false
bool judge3 = ary1.SequenceEqual(second: ary3);
judge3:true
全ての要素が一致するか?
Contains
// isContain : true
配列・シーケンス(列挙オブジェクト)作成
シーケンス(列挙オブジェクト)
IEnumerable<T>型変数
連結
List<int> myList = new List<int> { 0,0,0,0,0 };
var concat = numbers.Concat(second: myList);
⇒ 0 1 2 3 4 5 0 0 0 0 0
範囲・繰り返し
range : 1 2 3 4 5 6 7 8 9 10
var repeat = Enumerable.Repeat(element: "a", count: 5);
repeat : "a" "a" "a" "a" "a"
文字列 "aaaaa"ではない。配列。
空のシーケンス(列挙オブジェクト)作成
※シーケンス(列挙オブジェクト)≠配列。
IEnumerableを継承したオブジェクト
int cnt1 = ary1.Count();
cnt1:0
var ary2 = Enumerable.Empty<int>();
int cnt2 = ary2.Count();
cnt2:0
テキストファイルから
string[] s1 = File.ReadAllLines(@"D:\test.txt", Encoding.Default);
行単位で列挙オブジェクトに格納(遅延実行)
var s2 = File.ReadLines(@"D:\test.txt", Encoding.Default);
条件に合う行を列挙オブジェクトに格納(遅延実行)
var s3 = File.ReadLines(@"D:\test.txt", Encoding.Default).Where(x => x.Equals(@"test1"));
条件に合う行数を取得(遅延実行)
int cnt = File.ReadLines(@"D:\test.txt", Encoding.Default).Count(x => x.ToString().Contains(@"test"));
列挙オブジェクトの書込
static IEnumerable<string> returnString()
{
yield return @"test1";
yield return @"test2";
}
File.WriteAllLines(@"D:\test.txt", returnString());
File.WriteAllLines(@"D:\test.txt", Enumerable.Range(~));
ファイル情報
var files = Directory.EnumerateFiles(
path: @"D:\a", 検索開始ディレクトリ
searchPattern: "?0.txt", 検索パターン
searchOption: SearchOption.AllDirectories);
SearchOption.TopDirectoryOnly 指定ディレクトのみ
SearchOption.AllDirectories サブ・ディレクトも含める
files.ToList().ForEach(x => Console.WriteLine(x));
string fileNm1 = files.First();
string fileNm2 = files.Last();
var files = Directory.EnumerateDirectories(
path: @"D:\a", 検索開始ディレクトリ
searchPattern: "?0", 検索パターン
searchOption: SearchOption.AllDirectories);
SearchOption.TopDirectoryOnly 指定ディレクトのみ
SearchOption.AllDirectories サブ・ディレクトも含める
その他
畳み込み(fold・Aggregate)
var map = ary.Aggregate((pSum, elm) => pSum + elm);
右辺の結果を左辺の第一引数とする
第一引数の初期値は0? 第二引数は配列の値がLoopされる
pSum + elm → pSum
var map = ary.Aggregate((pMax, elm) => (pMax < elm) ? elm : pMax);
右辺の結果を左辺の第一引数とする
第一引数の初期値は0? 第二引数は配列の値がLoopされる
(pMax < elm) ? elm : pMax
if (pMax < elm) {
pMax = elm
}else{
pMax = pMax
}
var map = ary.Aggregate(10, (pCnt, elm) => pCnt += 1);
指定無し第一引数の初期値は0。 第二引数は配列の値がLoopされる
明示的に初期値を与える事も可能