4

マスターノードと子ノードが同じタイプのオブジェクト階層 (MasterNode -> ChildNodes) があり、このような 2 つのレベル (トップレベルと子) しかありません (「A」は D、E、F の親です。 B' は G の親など)

A--+
|  D
|  E
|  F
|
B--+
|  G
|
C--+
   H
   I

親オブジェクト (A、B、C) の IEnumerable としてMasterNodesがあり、親オブジェクトXを指定すると、 X.childrenによってその子の IEnumerable を取得できるとします。

SelectManyメソッドまたは

from parent in Masternodes
from child in parent.children
select child

これにより、次のシーケンスが得られます。

[D,E,F,G,H,I]

、しかし、これは私が求めているものではありません。

MasterNodes コレクション内のオブジェクトの深さ優先シーケンスを取得する LINQ クエリは何ですか? (最初の親、次にそのすべての子、次に次の親、そのすべての子などを返します)

期待される結果は、次のようなシーケンスになります。

[A,D,E,F,B,G,C,H,I]

更新

純粋な .NET 対応の LINQ を求めています。独自のメソッドを定義して実行できることはわかっていますが、フレームワークが提供するメソッドのみに基づいたものが必要です。

4

4 に答える 4

4

以下のようなクラスがある場合

public class Node
{
    public string Name;
    public List<Node> Children = new List<Node>();
}

あなたのlinqは

 Func<IEnumerable<Node>, IEnumerable<Node>> Flatten = null;
 Flatten = coll => coll.SelectMany(n=>n.Concat(Flatten(n.Children)));

テストコード:

Node[] roots = new Node[]{ new Node(){Name="A"},new Node(){Name="B"},new Node(){Name="C"} };
roots[0].Children.Add(new Node(){Name="D"});
roots[0].Children.Add(new Node(){Name="E"});
roots[0].Children.Add(new Node(){Name="F"});

roots[1].Children.Add(new Node(){Name="G"});

roots[2].Children.Add(new Node(){Name="H"});
roots[2].Children.Add(new Node(){Name="I"});

Func<IEnumerable<Node>, IEnumerable<Node>> Flatten = null;
Flatten = coll => coll.SelectMany(n=>n.Concat(Flatten(n.Children)));

var result = String.Join(",",Flatten(roots).Select(x=>x.Name));

Console.WriteLine(result);
于 2012-09-03T07:51:01.817 に答える
3

3 つ以上の階層レベルが必要な場合は、オブジェクト グラフを再帰的に処理する次の拡張メソッドを使用できます。

public static IEnumerable<T> Flat<T>(this IEnumerable<T> l, Func<T, IEnumerable<T>> f) =>
        l.SelectMany(i => new T[] { i }.Concat(f(i).Flat(f)));

データの親 - >子関係を記述する にをIEnumerable<T>マッピングする関数を使用して、指定された を平坦化します。TIEnumerable<T>

深さ優先の平坦化は、すべての要素をそのサブツリーと連結し、それらを で結合することによって行われますSelectMany

次のように使用できます。

var flattened = Masternodes.Flat(c => c.children);
于 2018-03-01T09:09:42.430 に答える
2

レベルが 2 つしかないため、次のアプローチが機能するはずです。

var result = (from parent in masternodes
              select new Node[] { parent }.Concat(parent.children)).SelectMany(i => i);

まず、親とその子の列挙型を作成します。

[A, D, E, F]
[B, G]
[C, H]

そして、それらを で平らにしSelectManyます。

于 2012-09-03T07:55:27.260 に答える
0

次のクラスがあるとします。

public class MasterNode : ChildNode
{
    public List<ChildNode> ChildNodes;
}

public class ChildNode
{
    public string Value;
}

それから

        List<MasterNode> list = new List<MasterNode>
        {
            new MasterNode
            {
                Value="A", 
                ChildNodes = new List<ChildNode>
                {
                    new ChildNode{Value = "D"},
                    new ChildNode{Value = "E"},
                    new ChildNode{Value = "F"}
                }
            },
            new MasterNode
            {
                Value="B", 
                ChildNodes = new List<ChildNode>
                {                        
                    new ChildNode{Value = "G"}
                }
            },
            new MasterNode
            {
                Value="C", 
                ChildNodes = new List<ChildNode>
                {
                    new ChildNode{Value = "H"},
                    new ChildNode{Value = "I"}
                }
            }
        };

        foreach (ChildNode c in list.SelectMany(l =>
                                {
                                   List<ChildNode> result = l.ChildNodes.ToList();
                                   result.Insert(0, l);
                                   return result;
                                }))
        {
            Console.WriteLine(c.Value);
        }
于 2012-09-03T07:41:22.487 に答える