🌲
【LINQ】Flatten() メソッド※
※更新
LINQ なのに IEnumerable<T> の拡張メソッドじゃないのはおかしい、と。
結果ツリーのノード側に要件が追加されちゃいましたが node.Flatten() で簡単に呼べるようになりました。
ソースコード
実行環境: https://dotnetfiddle.net/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace X
{
class Node : IEnumerable<Node> // node implements recursion interface
{
public Node? Parent;
public List<Node> Children = new();
public IEnumerator<Node> GetEnumerator() => Children.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(Node node) => Children.Add(node);
}
static class FlattenLinqExtensions
{
public static IEnumerable<T> Flatten<T>(this IEnumerable<T> source, FlattenStrategy strategy = FlattenStrategy.DepthFirst)
where T : IEnumerable<T>
{
if (source is T self)
{
yield return self;
}
foreach (var child in source)
{
foreach (var x in child.Flatten(strategy))
{
yield return x;
}
}
}
}
enum FlattenStrategy
{
DepthFirst,
BreadthFirst,
}
class Program
{
static void Main()
{
var node = new Node()
{
new Node()
{
new Node(),
new Node(),
},
new Node()
{
new Node(),
new Node(),
},
new Node()
{
new Node(),
new Node(),
},
};
var allNodes = node.Flatten();
int i = 0;
foreach (var n in node.Flatten())
{
i++;
Console.WriteLine($"{i}: {n.GetHashCode()}");
}
}
}
}
ノード側の実装が弄れない時用に、初版のメソッドを静的メソッドとして
IEnumerable<T> Enumerable.Flatten(T source, Func<T, IEnumerable<T>> selectMany);
にすれば完璧では?
初版
ツリー構造をフラットにするために SelectMany でアレコレやってたんですが、ふと思いつきました。
👇 勢いで Issue まで建てました。標準ライブラリにあったら良いなと思ったら、ぜひ Upvote を!
static IEnumerable<T> Flatten<T>(this T source, Func<T, IEnumerable<T>> selectMany)
{
yield return node;
foreach (var child in selectMany.Invoke(node))
{
foreach (var x in Flatten(child, selectMany))
{
yield return x;
}
}
}
以上です。お疲れ様でした。
Discussion