【技術書メモ】C#プログラミングのイディオム / 定石&パターン⑧
今回は、日付、時刻の操作方法。
DateTime構造体
DateTime構造体のインスタンス生成の主な方法と、よく使われるTodayプロパティとNowプロパティ。
// インスタンス生成 var dt1 = new DateTime(2016, 2, 15); var dt2 = new DateTime(2016, 2, 15, 8, 45, 20); // TodayとNowプロパティ var today = DateTime.Today; var now = DateTime.Now;
また、DateTime構造体には、年、月、日など、様々な日付および時刻の情報を、プロパティから参照することができる。
※ここでは割愛。
指定した日付の曜日の求め方。
var today = DateTime.Today; DayOfWeek dayOfWeek = today.DayOfWeek; if(dayOfWeek == DayOfWeek.Sunday) // DayOfWeekプロパティの型はDayOfWeek列挙型 public enum DayOfWeek { Sunday = 0, Monday = 1, Tuesday = 2, Wednesday = 3, Thursday = 4, Friday = 5, Saturday = 6
DayTime構造体を使用すれば、閏年の判定も可能。
var isLeapYear = DateTime.IsLeapYear(2016);
日付形式のもう字列をDateTimeオブジェクトに変換する方法。
DateTime dt1; if(DateTime.TryParse("2017/6/21", out dt1)) // 2017/06/21 0:00:00 Console.WriteLine(dt1); DateTime dt2; if(DateTime.TryParse("2017/6/21 10:41:38", out dt2)) // 2017/06/21 10:41:38 Console.WriteLine(dt2);
日時のフォーマット
日時を文字列に変換するには、ToStringメソッドを使用する。
ToStringの引数に、あらゆる書式を指定すると、結果の値も変わってくる。
var date = new DateTime(2016, 4, 7, 21, 6, 47); var s1 = date.ToString("d"); // 2016/04/07
日付を和暦で表示するには、DateTimeクラスを使用する。
var date = new DateTime(2016, 8, 15); var culture = new CultureInfo("ja-JP"); culture.DateTimeFormat.Calendar = new JapaneseCalendar(); var str = date.ToString("ggyy年M月d日", culture);
指定した日付の元号を得るには、DateTimeFormatInfoクラスのGetEraNameメソッドを使用する。
var date = new DateTime(1995, 8, 24); var culture = new CultureInfo("ja-JP"); culture.DateTimeFormat.Calendar = new JapaneseCalendar(); // 元号コードの取得 var era = culture.DateTimeFormat.Calendar.GetEra(date); // 元号コードから元号名を得る var eraName = culture.DateTimeFormat.GetEraName(era);
指定した日付の曜日を得るには、DateTimeFormatInfoクラスのGetDayNameメソッドを使用する。
var date = new DateTime(1998, 6, 25); var culture = new CultureInfo("ja-JP"); culture.DateTimeFormat.Calendar = new JapaneseCalendar(); // 曜日の取得 var dayOfWeek = culture.DateTimeFormat.GetDayName(date.DayOfWeek);
DateTimeの比較
日時を比較するには、比較演算子をそのまま利用できる。
var dt1 = new DateTime(2006, 10, 18, 1, 30, 21); var dt2 = new DateTime(2006, 11, 2, 18, 5, 28); if (dt1 < dt2) else if (dt1 == dt2)
時刻情報を含まない日付だけを比較する場合は、Dateプロパティを使う。
var dt1 = new DateTime(2001, 10, 25, 1, 30, 21); var dt2 = new DateTime(2001, 10, 25, 18, 5, 28); if (dt1.Date < dt2.Date) else if (dt1.Date == dt2.Date)
日時の計算
指定した時分秒後を求めるには、TimeSpan構造体を使用する。
var now = DateTime.Now; // TimeSpanオブジェクトを加える var future = now + now TimeSpan(1, 30, 0);
n日後、n日前の日付を求めるには、AddYears、AddMonthsメソッドを利用する。
var date = new DateTime(2009, 10, 22); var future = date.AddYears(2).AddMonths(5);
2つの日時の差を求める。
var date1 = new DateTime(2009, 10, 22, 1, 30, 20); var date2 = new DateTime(2009, 10, 22, 2, 40, 56); TimeSpan diff = date2 - date1; Console.WriteLine("差は、{0}日間{1}時間{2}分{3}秒です", diff.Days, diff.Hours, diff.Minutes, diff.Seconds); Console.WriteLine("トータルで{0}秒です", diff.TotalSeconds);
2つの日付の日数差を求める。
var date1 = new DateTime(2009, 10, 22, 1, 30, 20); var date2 = new DateTime(2009, 10, 22, 2, 40, 56); TimeSpan diff = date2.Date - date1.Date; Console.WriteLine("{0}日間", diff.Days);
DaysInMonth静的メソッドを使えば、月末日を求めれる。
var today = DateTime.Today; int day = DateTime.DaysInMonth(today.Year, today.Month); var endOfMonth = new DateTime(today.Year, today.Month, day);
DayOfYearプロパティを使って、1月1日からの通算日を求める。
var today = DateTime.Today;
int dayOfYear = today.DayOfYear;
【技術書メモ】C#プログラミングのイディオム / 定石&パターン⑦
今回はディクショナリの操作について。ディクショナリと聞くと馴染みがないが、JavaでいうMapと認識している。
ディクショナリの基本操作
ディクショナリの初期化。
var flowerDict = new Dictionary<string, int>() { {"sunflower", 400}, {"pansy", 300}, };
なお、ディクショナリにはオブジェクトも値に格納できる。
var employeeDict = new Dictionary<int, Employee> { {100, new Employee(100, "やまだ") }, };
では、続いて各操作を確認していく。
まずは、要素の追加から。
flowerDict["violet"] = 600; // Addメソッドを使う場合 flowerDict.Add("violet", 600);
要素を取り出す。
int price = flowerDict["rose"];
指定したキーにディクショナリが存在しない場合は、例外が発生してしまう。
そのため、ディクショナリにキーが存在しているか調べることができる。
var key = "pansy"; if (flowerDict.ContainsKey(key)) { }
ディクショナリから要素を削除する。
var result = flowerDict.Remove("pansy");
ディクショナリからすべての要素を取り出す。
foreach文を使うことになるが、foreachで取り出せる要素の型は、KeyValuePair
Keyプロパティでキーの値、Valueプロパティで対応する値を参照する。
foreach (var item in flowerDict) Console.WriteLine("{0} = {1}", item.Key, item.Value);
では、ディクショナリからすべてのキーを取り出す方法をみてみる。
foreach (var key in flowerDict.Keys)
ディクショナリの応用
配列やリストをディクショナリに変換する。
var employeeDict = employees.ToDictionary(emp => emp.Code);
ディクショナリから別のディクショナリを作成する。
ディクショナリからある条件に一致したものだけを抜き出し、新たにディクショナリを生成するなどの場合に用いられる。
var newDict = flowerDict.Where(x => x.Value >= 400).ToDictionary(flower => flower.Key, flower => flower.Value);
カスタマクラスをキーにする。
文字列や数値ではなく、独自に作成したカスタムクラスも、ディクショナリーのキーにできる。
ただ、これには一つだけ注意が必要で、キーに使用するカスタムクラスに、EqualsメソッドとGetHashCodeメソッドをオーバーライドする必要がある。
public int Day { get; private set; } public int Month { get; private set; } public MonthDay(int month, int day) { this.Month = month; this.Day = day; } public override bool Equals(object obj) { var other = obj as MonthDay; if (other == null) throw new ArgumentException(); return this.Day == other.Day && this.Month == other.Month; } public override int GetHashCode() { return Month.GetHashCode() * 31 + Day.GetHashCode(); }
public static void Main(string[] args) { var dict = new Dictionary<MonthDay, string> { {new MonthDay(3, 5), "珊瑚の日" }, {new MonthDay(8, 4), "箸の日" }, {new MonthDay(10, 3), "登山の日" }, }; var md = new MonthDay(8, 4); var s = dict[md]; Console.WriteLine(s); }
ディクショナリを使う際、キーがディクショナリに格納されていることが重要で、その値を利用しないケースがある。
こういった場合は、HashSet
var hash = new HashSet<string>(); hash.Add("string"); hash.OrderBy();
ディクショナリは、キーの重複を許していない。そのため、同一キーで複数のオブジェクトを関連づけることができない。
こういう場合は、値をリスト型にしておく。
var dict = new Dictionary<string, List<string>() { { "PC", new List<string> {"パーソナルコンピュータ", "プログラムカウンタ",}}, }
【技術書メモ】C#プログラミングのイディオム / 定石&パターン⑥
今回は、配列とList
配列とList
この章ではLINQのさらに詳しい使い方も説明してくれるらしいので、頑張ります。
要素の設定
配列あるいは、List
// List<T>(要素数:20個)の値を-1で埋める var numbers = Enumerable.Repeat(-1, 20).ToList(); // 配列(要素数:12個)の値をunknownで埋める var strings = Enumerable.Repeat("(unknown)", 12).ToArray();
配列あるいは、List
// 配列に1〜20の値を設定 var array = Enumerable.Range(1, 20).ToArray();
コレクションの集計
平均値の求め方。
var numbers = new List<int>{9, 7, 5, 4, 2, 5, 4, 0, 4, 1, 0, 4}; var average = numbers.Average(); // 合計の求め方 var sum = numbers.Sum();
最小値、最大値の求め方。
var numbers = new List<int>{9, 7, 5, 4, 2, 5, 4, 0, 4, 1, 0, 4}; var min = numbers.Where(n => n > 0).Min(); var max = numbers.Where(n => n > 0).Max();
条件に一致する要素をカウントする。
var count = numbers.Count(n => n == 0);
コレクションの判定
条件に一致する要素があるかどうか調べる。
Anyメソッドは、条件に一致する要素が見つかった時点で要素の取得を中止する。
bool exists = numbers.Any(n => n % 7 == 0);
コレクション内のすべての要素が条件を満たしているかどうかを調べる。
bool isAllPositive = numbers.All(n => n > 0);
2つのコレクションの要素が等しいか調べる。
bool equal = numbers1.SequenceEqual(numbers2);
単一の要素の取得
条件に一致する最初、または最後の要素を取得する。
var word = words.FirstOrDefault(x => x.Length == 4); var word = words.LastOrDefault(x => x.Length == 4);
条件に一致する最初、または最後のインデックスを求める。
var index = numbers.FindIndex(n => n < 0); var index = numbers.FindLastIndex(n => n < 0);
複数の要素の取得
条件を満たす要素をn個取り出す。
var results = numbers.Where(n => n > 0).Take(5);
コレクションの中から、条件を満たしている間だけ要素を取り出す。
例として、400, 281, 389, 637, 411というリストがあった場合、600以下という条件をつけたら、先頭の400、281、389だけ取れるというもの。
var selected = books.TakeWhile(x => x.Price < 600);
では逆に、条件を満たしている間だけ要素を読み飛ばすには、SkipWhile演算子を使う。
var selected = numbers.SkipWhile(n => n >= 0).ToList();
その他の処理
コレクションから別のコレクションを生成する。
基本的には、ToArray()、ToList()メソッドを使用する。
var words = new List<string>{"Microsoft", "Apple", "Google", "Oracle", }; var lowers = words.Select(name => name.ToLower()).ToArray();
重複を排除する。
var result = numbers.Distinct();
コレクションを並び替える。
// 昇順にソート var sorteBooks = books.OrderBy(x => x.Price); // 降順にソート var sortedBooks = books.OrderByDescending(x => x.Price);
2つのコレクションを連結する。
var allfiles = files1.Concat(file2);
【技術書メモ】C#プログラミングのイディオム / 定石&パターン⑤
今回は文字列操作編!
そういえば、会社の研修でJavaを勉強し始めた当初、文字列の比較のやり方がわからなくて、かなりつまづいたな。
結局、10才近く年下の子にやり方教えてもらったのは、いい思い出です。
文字列の比較
C#での文字列比較をやっていきます。
まず、これが一番シンプルな比較方法。大文字小文字も区別される。
if (str1 == str2)
次が、大文字小文字の区別なく比較する方法。
3つ目の引数のtrueが、大文字小文字の区別なく比較することを表している。
if (String.Compare(str1, str2, ignoreCasetrue) == 0)
ひらがなとカタカナを区別なく、比較することも可能。
var str1 = "カステラ"; var str2 = "かすてら"; var cultureInfo = new CultureInfo("ja-JP"); if(String.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreKanaType) == 0)
全角半角の区別なく比較するには
var str1 = "HTML5"; var str2 = "HTML5"; var cultureInfo = new CultureInfo("ja-JP"); if(String.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreWidth) == 0)
また、String.Compareメソッドの第3引数は論理演算子で繋げることも可能で
var str1 = "Html5"; var str2 = "HTML5"; var cultureInfo = new CultureInfo("ja-JP"); // 大文字小文字と全角半角の区別なく比較 if (string.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase) == 0)
文字列の判定
nullあるいは空文字かを判定。これはよく使いそう。
if(String.IsNullOrEmpty(str))
空文字かを判定する。
if(str == String.Empty)
nullか空文字か空白文字列かを判定する。空白文字列も判定できるのか。
if(String.IsNullOrWhiteSpace(str))
指定した文字列で始まっているか。
if(str.StartsWith("Visual"))
指定した文字列で終わっているか。
if(str.EndsWith("Exception"))
指定した部分文字列が含まれているか。
if(str.Contains("Program"))
上記は文字列だったが、文字が含まれているかを調べるには、LINQを使う。
var target = "The quick brown fox jumps over the lazy dog."; var contains = target.Contains('b');
次もまたLINQ。条件を満たしている文字が含まれているか。
var target = "C# Programming"; // 小文字が含まれているかチェック var isExists = target.Any(c => Char.IsLower(c));
上記はどれか1文字でも条件を満たしているかどうかのチェックだったが、今度はすべての文字が条件を見てしているかをチェックする。
var target = "141421536"; // 数字かどうかをチェック var isAllDigits = target.All(c => Char.IsDigit(c));
文字列の検索と抽出
部分文字列を検索し、その位置を求める。
var target = "NameList;BirthdayList"; var index = target.IndexOf("BirthdayList");
文字列の一部を取り出す。
// 指定した位置から最後までを部分文字列として取り出す var value = target.Substring(index);
取り出す長さを指定することもできる.
var value = target.Substring(index, endIndex - startIndex);
文字列の変換
文字列の前後の空白を取り除く。
var replaced = target.Trim();
文字列の前後片方だけの空白を取り除く。
var replaced1 = target.TrimStart(); var replaced2 = target.TrimEnd();
指定した位置から任意の数の文字を削除する。
var result = target.Remove(5, 3);
指定した位置に文字列を挿入する。
var target = "01234"; // 01abc234が出力される var result = target.Insert(2, "abc");
文字列の一部を別の文字列で置き換える。
var target = "I hope you could come to with us."; // I wish you could come to with us.と出力される。 var replaced = target.Replace("hope", "wish");
小文字を大文字に変換する。
var replaced = target.ToUpper();
大文字を小文字に変換する。
var replaced = target.ToLower();
文字列の連結と分割
var name = "山田" + "太郎";
文字列の末尾に追加する。
var name = "やまだ"; name += "先生";
指定した区切り文字で文字列配列を連結する。
var languages = new[]{"C#", "Java", "VB", "Ruby", }; var separator = ","; // C#, Java, VB, Rubyと出力される var result = String.Join(separator, languages); 指定した文字で文字列を分割する。 >|cs| var target = "I hope you could come to with us."; // 空白文字で分割する string[] words = target.Split(' ');
なお、空の配列要素を含めないようにするには、以下の書き方が必要。
var target = "I hope you could come to with us."; // 空白文字で分割する string[] words = target.Split(new [] {' ', '.'}, StringSplitOptions.RemoveEmptyEntries);
文字列は基本的に普変オブジェクトである。そのため、文字連結を行うたびに、新たなインスタンスを生成していることになる。
そこで、StringBuilderを使った文字連結がある。StringBuilderクラスは、インスタンス生成時に、文字列を格納する領域を確保し、その領域を超えて文字列を追加しようとした場合は、自動的に容量が増えていく。そのため、無駄なインスタンスを生成する必要がない。
var sb = new StringBuilder(); foreach (var word in GetWords()) { sb.Append(word); } // 文字列に変換 var text = sb.ToString();
その他の文字列操作
文字列から文字を1つずつ取り出すには、foreach文を使う。
foreach (var c in str) { }
文字配列から文字列を生成する。
var chars = new char[] {'P', 'r', 'o', 'g', 'r', 'a', 'm' }; var str = new string(chars);
数値を文字列に変換するには、ToStringメソッドを使用する。
ToStringメソッドには、さまざまな書式指定を引数で行えるが、多すぎるのでここでは割愛する。
指定した書式で文字列を整形するには、String.Formatメソッドを使用する。
var novelist = "やまだ"; var bestWork = "春麗"; var bookline = String.Format("Novelist={0};BestWork={1}", novelist, bestWork);
【技術書メモ】C#プログラミングのイディオム / 定石&パターン④
本のタイトルにもなっているイディオム。
そもそもイディオムって何だろうと思っていたが、これはコーディングレベルでよく利用される汎用的なコードのこと。
なので、このイディオムを覚えれば、品質もよく、正しいコードを書けることに繋がりそう。特に自分が書いているコードって、思い通りには動くけど、プログラム上級者の人から見たら、どう思われるかいつも心配なので。。
初期化に関するイディオム
変数の宣言と初期化は同時に行うこと。
var age = 25;
配列とリストの初期化
初期化構文を使おう。初期化構文を使うと、要素の入れ替えや追加が楽になるから。
// 配列 var langs = new string[] { "C#", "VB", "C++", }; // リスト var nums = new List<int> { 10, 20, 30, 40, };
Dictionaryの初期化
こちらも同じく初期化構文を使おう。
// Dictionary var dict = new Dictionary<string, string>() { {"ja", "日本語" }, {"en", "英語" }, {"es", "スペイン語" }, {"de", "ドイツ語" }, };
オブジェクトの初期化
こちらも同じく初期化構文を使用する。オブジェクト生成とプロパティの初期化が同時に行える。
var person = new Person { Name = "山田太郎", Birthday = new DateTime(1995, 11, 23), };
初期化構文の特徴として、「要素の入れ替えや追加が容易になる」、「可読性が高まる」といった特徴がある。
判定のイディオム
単純な比較。
// 年齢が10才以下かという人の思考に基づく考え方 if (age <= 10)
数値が範囲内にあるかどうか。
// 数値を直線上に並べた比較 if(MinValue <= num && num <= MaxValue)
if文の中でのreturn文の使い方。
このように記載すれば、可読性が高まる。
// ふるいにかけて残ったものだけ処理する if (filePath == null) return; if (GetOption() == Option.Skip) return; // 実行したい処理
繰り返しのイディオム
ループ処理の考え方は、LINQ > foreach > forの順番で適用を考える。
なお、List
var nums = new List<int> { 1, 2, 3, 4, 5, }; // 12345と出力される nums.ForEach(n => Console.Write("{0}", n));
条件演算子、null合体演算子によるイディオム
条件演算子
// trueなら1、falseなら0を返却 var num = list.Contains(key) ? 1 : 0;
null合体演算子
// GetMessageがNULLを返却したら、DefaultMessageの値を変数messageにつめる
var message = GetMessage(code) ?? DefaultMessage();
null条件演算子
// sale変数がnullのとき、Productプロパティにアクセスせずにnullを返却する。 // NullPointerExceptionが発生しない return sale?.Product;
プロパティに関するイディオム
まずは、プロパティの初期化。コンストラクタに初期化処理を書かなくていい。
Javaで慣れている分、プロパティにまだまだ慣れないが。。
// プロパティの初期化 public int MinimumLength { get; set; } = 6;
次が、値を変更できない読み取り専用のプロパティの定義方法。
こう定義すると、外のクラスから値の変更はできなくなる。
public int MinimumLength { get; private set; }
メソッドに関するイディオム
可変長引数。引数の数を限定したくない場合に使用する。
Javaでいうオーバーロードするところを、引数の数の違いだけなら、この書き方で吸収できるというもの。
// 定義 public void WriteInt(params int[] args) { foreach(var db in args) { Console.WriteLine(db); } } // 実際の呼び出し方 pp.WriteInt(1, 2, 3, 4, 5);
次にオプション引数。引数を省略した際の初期値を、それぞれ設定できるというもの。
// 定義 public void DoSomething(int num, string message = "失敗しました", int retryCount = 3) { Console.WriteLine("{0},{1},{2}",num, message, retryCount); } // 実際の呼び出し方 pp.DoSomething(100); pp.DoSomething(100, "エラーです"); pp.DoSomething(100, "エラーです", 5);
その他のイディオム
ファイルパスの指定には、先頭に@を付加した逐次的リテラル文字列を使用する。
そうすると、¥記号がエスケープ文字として認識されなく、ファイルパスがそのまま記述可能。
var path = @"C:¥Example¥Greeting.txt";
2つの要素を入れ替える。
var temp = a; a = b; b = temp;
文字列を数値に変換する。
TryParseメソッドを使用する。エラーハンドリングも行ってくれて、便利!
int height; if (int.TryParse(str, out height)) { // 変換に成功したときの処理 } else { // 変換に失敗したときの処理 }
MacBook Pro 13-inch, Mid 2010のメモリを16GBに増設した
最近はWindowsをメインマシンとしてきたが、Windowsが謎のフリーズを繰り返すようになり、仕方なく昔のMacを引っ張り出してきた。それが、MacBook Pro 13-inch, Mid2010だ。もう10年近く前に買ったことになる。
で、Macは起動はするのだが、何をするにも遅い。そこで、メモリを増設することにした。で、何も考えずに16GBに増設しようと考え、以下のメモリを購入する。
シリコンパワー ノートPC用メモリ DDR3 1600 PC3-12800 8GB×2枚 204Pin Mac 対応 永久保証 SP016GBSTU160N22
- 出版社/メーカー: シリコンパワー
- 発売日: 2012/09/01
- メディア: 付属品
- 購入: 12人 クリック: 34回
- この商品を含むブログ (9件) を見る
で、交換作業自体はうまくいったが、何とMacが起動しない。いろいろ調べてみると、そもそもMacBook Pro 13-inch Mid 2010は16GBに公式には対応してないとのこと。
また、メモリは相性がいろいろあるらしく、結果自分が買ったメモリはうちのMacには合わなかったということらしい。。
そこで、もう一度調べていくと、MacBook Pro 13-inch Mid 2010と動確が取れてるメモリはいくつかあるが、Amazonから買えるメモリは以下のものだった。
Team ノートPC用メモリ SO-DIMM-DDR3 永久保証 ECOパッケージ (1066Mhz PC3-8500 1.5V 8GBx2)
- 出版社/メーカー: Team
- メディア: エレクトロニクス
- この商品を含むブログを見る
さっそく交換して、起動してみると起動したー!!
がしかし、MacBook Proの内蔵キーボードが反応しない。USB端子で接続している外部キーボードは反応するという謎事象。。
で、試して成功したのが、PRAMリセット。ようやく、メモリ交換が成功しました。
MacBook Pro 13-inch, Mid 2010で、メモリを16GBに増設することを検討している方は、この記事が参考になれば!
【技術書メモ】C#プログラミングのイディオム / 定石&パターン③
ラムダ式
ラムダ式は一種のメソッドで、メソッドをかなり簡略化することができる。
public void Do() { var numbers = new[] { 5, 3, 9, 6, 7, 5, 8, 1, 0, 5, 10, 4 }; // 変数judgeに処理内容を代入 Predicate<int> judge = (int n) => { if (n % 2 == 0) { return true; } else { return false; } }; // Countメソッドの呼び出し var count = Count(numbers, judge); } // 第2引数のjudgeには、int型を受け取り、bool値を返すメソッドを指定可 public int Count(int[] numbers, Predicate<int> judge) { int count = 0; foreach(var n in numbers) { if(judge(n) == true) { count++; } } return count; }
上記のようなソースがあったとして、変数judgeに代入している処理は、ラムダ式でだいぶ簡略化できる。
- returnの右側には、式を書ける。
- ラムダ式の{}が1つであれば、{}とreturnを省略可。
- 引数の型を明示しなくてもよい。
- 引数が1つであれば、()を省略可。
省略したソースがこちら。
var count = Count(numbers, n => n % 2 == 0);
とかなり省略できるが、ラムダ式は全然慣れてないので、初見だと何をやっているかわからない。また、Predicateの理解も曖昧だし、メソッドの引数にメソッドを指定するって考え方もピンとこない。慣れたら、便利なのかな。
Listクラスとラムダ式の組み合わせ
List
まずは、以下Listがあるとする。
var list = new List<string> { "Tokyo", "New Delhi", "Bankok", "london", "Paris", "Berlin", "Canbera", "Hong Kong" };
このListに対して、ラムダ式を使ったメソッド呼び出し例を記載していく。
Existsメソッド
// 引数で指定した条件に一致する要素がするかをtrue / falseで返却 // 最初の文字が'A'である要素がリスト内に存在するかチェック var exists = list.Exists(s => s[0] == 'A');
Findメソッド
// 引数で指定した条件と一致する要素を検索し、最初に見つかった要素を返却 // 文字列の長さが6文字の最初の要素を返却する(Bankok) var name = list.Find(s => s.Length == 6);
FindIndexメソッド
// 引数で指定した条件と一致する要素を検索し、インデックスを返却 // 要素の中からBerlinを検索し、そのインデックスを返却 int index = list.FindIndex(s => s == "Berlin"); Console.WriteLine(index);
FindAllメソッド
// 引数で指定した条件と一致する、すべての要素を取得する // Tokyo, Parisを取得(文字列が5文字以下) var names = list.FindAll(s => s.Length <= 5); foreach (var s in names) { Console.WriteLine(s); }
RemoveAllメソッド
// 引数で指定した条件と一致すよ要素をリストから削除し、戻り値は削除した要素数 // London, Hong Kongを削除 var removedCount = list.RemoveAll(s => s.Contains("on")); Console.WriteLine(removedCount);
ForEachメソッド
// リストの各要素に対して引数で指定した処理を実行 list.ForEach(s => Console.WriteLine(s)); // 上と下は同じこと foreach(var s in list) { Console.WriteLine(s); }
ConvertAllメソッド
// リスト内の要素を別の型に変換し、変換された要素が格納されたリストを返却
var lowerList = list.ConvertAll(s => s.ToLower());
lowerList.ForEach(s => Console.WriteLine(s));
LINQ to Objectsの基礎
まず、LINQの概要としては、オブジェクト、データベース、XMLなどのさまざまなデータに対して標準化された方法で問い合わせできるというもの。自分の中では、ソースに対して実施できるSQLのイメージできる。(selectやwhereなどがあるから)
また、クエリ演算子はIEnumerable
ここでクエリ演算子の例を一つ。
// Whereで5文字以下の要素に絞り、Selectで、引数にラムダ式で小文字変換を指定し、その結果を出力 IEnumerable<string> query = list.Where(s => s.Length <= 5).Select(s => s.ToLower());
※シーケンスとは
標準クエリ演算子の捜査対象のデータのこと。(配列やList
IEnumerable
遅延実行と即時実行
遅延実行とは、本当にデータが必要になったときにクエリが実行されて、LINQの大きな特徴の一つ。
var list = new List<string> { "Tokyo", "New Delhi", "Bankok", "london", "Paris", "Berlin", "Canbera", "Hong Kong" }; // ここで変数queryに値を代入しているようにみえるが、実際は検索結果が代入されていない var query = list.Where(s => s.Length <= 5); list[0] = "Osaka"; // 値が実際に必要になったタイミングで、クエリ演算子が実行される。 // そのため、実行結果は"Osaka","Paris" foreach(var i in query) { Console.WriteLine(i); }
即時実行とは、クエリを明示的に実行させることをいう。ここでは、ToArrayメソッドを使用した例を示す。
var list = new List<string> { "Tokyo", "New Delhi", "Bankok", "london", "Paris", "Berlin", "Canbera", "Hong Kong" }; // ここで、Whereメソッド実行 var query = list.Where(s => s.Length <= 5).ToArray(); list[0] = "Osaka"; // すでにWhereメソッドが実行されているため、実行結果は"Tokyo","Paris" foreach(var i in query) { Console.WriteLine(i); }