Advent LINQ (5): Flatten

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

投稿者:

kekyo

A strawberry red slime mold. Likes metaprogramming. MA. Bicycle rider. http://amzn.to/1SeuUwD