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にも応用可能。