1. 概要
他のページで、「List」のコピーについて書いていますが。
ここでは、「List」から別のリストを作成する方法について・・・。
本ページは、下記のサイトを参考にさせていただきました。
「Listから重複した要素を削除するには?[C#/VB]」
「【LINQ】任意のクラスでDistinctを使う方法」
「【LINQ】GroupByを使ってリストを分類する」
2. 一部の要素で List 作成
public class myClass
{
public int age = 0;
public string name = String.Empty;
}
List<myClass> list01 = new List<myClass>
{
new myClass { age = 22, name = "hogehoge" },
new myClass { age = 21, name = "fugafuga" },
new myClass { age = 20, name = "piyopiyo" },
};
てな状態のクラスがあるとして、これのうち「name」要素から「List<string>」を作成しようとすると、長ったらしくは
List<string> list02 = new List<string>();
foreach (myClass item in list01)
{
list02.Add(item.name);
}
となりますが、下の3行は、まとめて、下記の1行にできます。
すっきりして読みやすくていいですね。
list01.ForEach(x => { list02.Add(x.name); });
3. ソートして別のリストを作成
前項のリストをソートして別のリストを作成します。
「name」の順にしますと
List<myClass> list02 = list01.OrderBy(x => x.name).ToList();
てな書き方ができます。
foreach (myClass m in list02)
{
Console.WriteLine("age = [" + m.age + "] name[" + m.name + "]");
}
で出力すると
age = [21] name[fugafuga]
age = [22] name[hogehoge]
age = [20] name[piyopiyo]
と、先頭とその次が入れ替わっていますね。
気をつけなければならないのは、「OrderBy」を含んだ行をいれると、「using」を1行追加しないと
error CS1061: Type 'System.Collections.Generic.List<myClass>' does not contain a definition for 'OrderBy' and no extension method 'OrderBy' of type 'System.Collections.Generic.List<myClass>' could be found. Are you missing `System.Linq' using directive?
/usr/local/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)
てなエラーになります。
突如
using System.Linq;
が必要になるのですな。
ここいらのしかけがよくわかっていない。
4. 重複削除
これも「using System.Linq;」が必要です。
「Distinct」というメソッドを使います。
List<string> list01 = new List<string>{ "あ", "あ", "い", "う", "え", "お", "あ", "お", };
var list02 = list01.Distinct();
list01.ForEach(x => Console.Write(x));
Console.WriteLine();
foreach (var item in list02)
{
Console.Write(item);
}
Console.WriteLine();
上記のソースでロードモジュールを作成して、実行すると下記の結果が得られます。
ああいうえおあお
あいうえお
これもよくわからないのは、返す型は、「var」になるという・・・。
「var」の箇所を「List<string>」へ変えると
error CS0266: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to 'System.Collections.Generic.List<string>'. An explicit conversion exists (are you missing a cast?)
てな、エラーになっちゃいます。
また、これが単純な「string」の配列なので、簡単なのですが。
複雑なクラスの配列の場合、等価を判断する「IEquatable」てなものを実装する必要があるらしい。
もしくは、「Sort」時に、「Compare」を実装したクラスを引数として渡すように、「IEqualityComparer」を実装したクラスを「Distinct」へ渡すといいらしい。
まだ、やってみてないですけどね。
5. グループ化
「List」の一部をグループ化して、別のリストを作成することができます。
これも「using System.Linq;」が必要になります。
下記のようなコードを書いてみました。
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
public class myClass
{
public int age = 0;
public string name = String.Empty;
}
public class HelloWorld
{
static public void Main ()
{
List<myClass> list01 = new List<myClass>
{
new myClass { age = 22, name = "山田 太郎" },
new myClass { age = 21, name = "山田 次郎" },
new myClass { age = 20, name = "田中 三郎" },
new myClass { age = 20, name = "田中 史郎" },
};
var SurnameList = list01.GroupBy(x => x.name.Substring(0, 2)).Select(y => new { SurName = y.Key.ToString() });
foreach (var Surname in SurnameList)
{
Console.WriteLine("Surname = [" + Surname + "]");
}
}
}
名簿から、「姓」が同じ人を抜き出して、グループ化しているわけです。
25行目の「Substring(0, 2)」は、バイト数でなく文字数なのでね。
スマートには、姓と名を半角で分割したいところではあります。
コンパイルして、実行すると下記の結果が得られます。
Surname = [{ SurName = 山田 }]
Surname = [{ SurName = 田中 }]