2016-07-24 3 views
-2

LAMQを使用して親アイテムを(親子依存のために)リストの最初に置くLINQクエリを書く正しい方法は何ですか?親子関係をLAMBDAと発注する方法は?

たとえば期待される出力は、すべてのフィールドID、文字列型の親会社)との順序付きリスト(「階層命名オブジェクトタイプ)でなければなりません:

  • ID親
  • A2ヌル
  • A1 A2
  • A5 A2(A2に依存)
  • A3 A2
  • A4 A5(A5に依存)
+0

可能性のある重複した[親を持つエンティティの注文方法/子の関係を一緒にリスト](http://stackoverflow.com/questions/19008347/how-to-order-entities-with-parent-child-relationship-together-in-a-list) –

+0

どのようなタイプですかリストの中のオブジェクトとリストの中の?あなたが書いたものから、それらの文字列ですか? – Tschareck

+0

A1がリストの前にA5が表示されるのはなぜですか(両方とも同じ親を共有しています)?出力のための特定のルールはありますか? – user3185569

答えて

0

通常、ツリートラバーサルは何らかの再帰を必要とし、C#は言語として名前付きラムダ式をサポートしていないので(名前付き関数式のJavaScriptコンセプトとは異なります)、純粋な方法でこのタスクをクリーンに実行する方法はないと思いますlambdaを使用したLINQクエリ。

関数の代理人を外部から宣言したい場合は、かなり可能です。ただし、このコードでは、ツリーを構築する従来の再帰メソッドには明確な利点はありませんが、実装のLINQ /ラムダバージョンを示しています。

IEnumerable<ItemType> items = new[] 
{ 
    new ItemType() { ID = "A4", ParentID = "A5"}, 
    new ItemType() { ID = "A5", ParentID = "A2"}, 
    new ItemType() { ID = "A1", ParentID = "A2"}, 
    new ItemType() { ID = "A3", ParentID = "A2"}, 
    new ItemType() { ID = "A2", ParentID = null }, 

}; 

var childrenLookup = items.ToLookup(i => i.ParentID); 

Func<ItemType, IEnumerable<ItemType>> preOrderTraverse = null; 
preOrderTraverse = new Func<ItemType, IEnumerable<ItemType>>(item => 
{ 
    var curNode = Enumerable.Repeat(item, 1); 
    var childNodes = childrenLookup[item.ID] 
     .OrderBy(i => i.ID)     // Sort siblings by ID 
     .SelectMany(preOrderTraverse); 

    return Enumerable.Union(curNode, childNodes); 
}); 

var preOrderTraversal = childrenLookup[null].SelectMany(preOrderTraverse); 

foreach(var item in preOrderTraversal) 
    Console.WriteLine($"{item.ID}, {item.ParentID}"); 

とコードの出力は次のとおりです:ここで

は再帰と(効率のための)ルックアップテーブルを使用した例であるの

 
A2, 
A1, A2 
A3, A2 
A5, A2 
A4, A5