|
.NET TIPS
オブジェクトのコレクションをプロパティ値によりグループ化するには?[3.5、C#、VB]
デジタルアドバンテージ 遠藤 孝信
2010/03/11 |
|
|
コレクション内のオブジェクトを、そのオブジェクトの特定のプロパティ値でグループ化(グルーピング)し、グループごとにオブジェクトを列挙するといった処理は、表示処理などでもよく必要となる。
.NET Framework 3.5以降では、この種のグループ化処理は、LINQを使えば比較的簡単だ。本稿では、グループ化を行うLINQの基本的な記述例を示す。
ファイル一覧を拡張子でグループ化
以下に示しているサンプル・プログラムは、C:\Windowsにある全ファイルを取得し、それらのファイルを拡張子でグループ化して、拡張子ごとにファイルを一覧表示する。
サンプル・プログラムを実行すると、次のようなファイル一覧が表示される。
.bin
ativpsrm.bin
mib.bin
.dat
bootstat.dat
nsreg.dat
.dll
twain.dll
twain_32.dll
.exe
bfsvc.exe
explorer.exe
fveupdate.exe
HelpPane.exe
hh.exe
……以下省略……
|
|
サンプル・プログラムの実行結果(例) |
全ファイルの取得は、DirectoryInfoクラス(System.IO名前空間)のGetFilesメソッドで行える。このメソッドの戻り値は、ファイルの情報を格納したFileInfoクラス(System.IO名前空間)のオブジェクトの配列である。ファイルの拡張子は、Extensionプロパティ、ファイル名はNameプロパティから取得できる。
// grouping1.cs
using System;
using System.IO;
using System.Linq;
class Program {
static void Main() {
var windir = new DirectoryInfo("C:\\Windows");
FileInfo[] files = windir.GetFiles();
// LINQのクエリ
var query = from n in files
group n by n.Extension into g
orderby g.Key
select new { Extension = g.Key, Files = g };
foreach (var ext in query) {
Console.WriteLine(ext.Extension); // 拡張子を表示
foreach (var file in ext.Files) {
Console.WriteLine("\t" + file.Name); // ファイル名を表示
}
}
}
}
// コンパイル方法:csc grouping1.cs
|
' grouping1.vb
Imports System.IO
Imports System.Linq
Class Program
Shared Sub Main()
Dim windir = New DirectoryInfo("C:\Windows")
Dim fileInfos As FileInfo() = windir.GetFiles()
' LINQのクエリ
Dim query = From n In fileInfos _
Group n By ext = n.Extension Into g = Group _
Order By ext _
Select New With { .Extension = ext, .Files = g }
For Each ext In query
Console.WriteLine(ext.Extension) ' 拡張子を表示
For Each file In ext.Files
Console.WriteLine(vbTab & file.Name) ' ファイル名を表示
Next
Next
End Sub
End Class
' コンパイル方法:vbc grouping1.vb
|
|
拡張子ごとにファイル名を一覧表示するサンプル・プログラム(上:C#、下:VB) |
最初のポイントとなるのは、グループ化を行うためのgroup句だ。
group n by n.Extension into g
|
Group n By ext = n.Extension Into g = Group _
|
|
グループ化を行うためのLINQのgroup句(上:C#、下:VB) |
コード内の「〜 by n.Extension 〜」の記述より、オブジェクトのシーケンス(=並び)は、Extensionプロパティによりグループ化される。また、「〜 into g 〜」の記述により、各グループのシーケンスは、変数gにより参照できるようになる。
もう1つのポイントは、グループ化に使用したキー(今回の場合はExtensionプロパティの値)の参照であるが、C#では、グループのKeyプロパティによりキーが取得でき、VBではgroup句の記述時に付けた名前(ここでは「ext」)でキーにアクセスできる。
select new { Extension = g.Key, Files = g };
|
Select New With { .Extension = ext, .Files = g }
|
|
グループ化を行ったキーとグループへのアクセス(上:C#、下:VB) |
このselect句では、グループ化したキーを(匿名クラスの)Extensionプロパティに設定し、グループ化後のシーケンス(FileInfoオブジェクトのコレクション)をFilesプロパティに設定している。
いずれにせよ、グループのシーケンスまでを一覧表示するには、上記のサンプル・プログラムのように、2重のforeach/For Each文が必要となる。
拡張子の統一とグループ内でのソート
上記のサンプル・プログラムのクエリは最低限の記述例を示しただけであるため、最後にもう少し機能を追加しておこう。
1つは、キーの大文字小文字の違いによりグループが異なってしまうため(例:「.INI」と「.ini」)、これを統一する。もう1つは、今回の例では不要だが、グループ内の項目をソートする場合の記述だ。この2点を修正したコードを以下に示す。
// grouping2.cs
using System;
using System.IO;
using System.Linq;
class Program {
static void Main() {
var windir = new DirectoryInfo("C:\\Windows");
FileInfo[] files = windir.GetFiles();
// LINQのクエリ
var query = from n in files
group n by n.Extension.ToLower() into g
orderby g.Key
select new {
Extension = g.Key,
Files = from m in g
orderby m.Name
select m
};
foreach (var ext in query) {
Console.WriteLine(ext.Extension); // 拡張子を表示
foreach (var file in ext.Files) {
Console.WriteLine("\t" + file.Name); // ファイル名を表示
}
}
}
}
// コンパイル方法:csc grouping2.cs
|
' grouping2.vb
Imports System.IO
Imports System.Linq
Class Program
Shared Sub Main()
Dim windir = New DirectoryInfo("C:\Windows")
Dim fileInfos As FileInfo() = windir.GetFiles()
' LINQのクエリ
Dim query = From n In fileInfos _
Group n By ext = n.Extension.ToLower() _
Into g = Group _
Order By ext _
Select New With { _
.Extension = ext, _
.Files = _
From m In g Order By m.Name Select m _
}
For Each ext In query
Console.WriteLine(ext.Extension) ' 拡張子を表示
For Each file In ext.Files
Console.WriteLine(vbTab & file.Name) ' ファイル名を表示
Next
Next
End Sub
End Class
' コンパイル方法:vbc grouping2.vb
|
|
拡張子の統一とグループ内でのソートを行ったサンプル・プログラム(上:C#、下:VB) |
このように、各グループ内でのソートは、グループ化の結果(変数g)を利用して、入れ子状にクエリを記述すればよい。
利用可能バージョン:.NET Framework 3.5以降
カテゴリ:クラス・ライブラリ 処理対象:LINQ
使用ライブラリ:DirectoryInfoクラス(System.IO名前空間)
使用ライブラリ:FileInfoクラス(System.IO名前空間)
|
|
generated by
|
|
Insider.NET 記事ランキング
本日
月間