Advent LINQ (3)で、フォルダを探索しながらファイルを列挙するFilesAsEnumerableを作った。このような、木構造のシーケンスを探索するというシチュエーションは、色々ありそうだ。なので、このアルゴリズムを一般化する事を考える。
public static class LinqExtensions
{
public static IEnumerable<U> Flatten<T, U>(
this T node,
Func<T, IEnumerable<T>> predictBySubNode,
Func<T, IEnumerable<U>> predictByNode)
{
var bySubNode =
from subNode in predictBySubNode(node)
from childNode in Flatten(subNode, predictBySubNode, predictByNode)
select childNode;
var byNode =
from childNode in predictByNode(node)
select childNode;
return bySubNode.Concat(byNode);
}
}
これを使ってファイルの探索を行うには、以下のように記述する。
var baseDirectory = new DirectoryInfo(@"C:project");
foreach (var file in baseDirectory.Flatten(
directory => directory.GetDirectories(),
directory => directory.GetFiles("*.cs")))
{
Console.WriteLine(file.FullName);
}
XmlDocumentから、テキストノードを抜き出してみる。
var document = new XmlDocument();
document.Load(@"C:projectdata.xml");
foreach (var text in document.DocumentElement.Flatten(
element => element.SelectNodes("*").Cast<XmlElement>(),
element => element.SelectNodes("text()").Cast<XmlText>()))
{
Console.WriteLine(text.Value);
}
もちろん、XDocumentにも応用可能。