3

これが私が作ったクラスです:

public class ItemTree
{

    public Int32 id { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public String text { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<ItemTree> item { get; set; }

    public int parentId { get; set; }

}

そして、これが私がそれを使用する方法です:

var tree = new ItemTree();
tree.id = 0;
tree.text = "sometext";
tree.item = new List<ItemTree>();

foreach (...)
{
    if (tree.item.Count == 0)
    {
      tree.item.Add(new ItemTree
      {
        id = my_id,
        text = my_name,
        item = new List<ItemTree>(),
        parentId = my_par
      });
    }
    else
    {
      tree.item.Where(x => x.id == my_par)
               .Select(x => x.item)
               .First()
               .Add(new ItemTree 
               {
                 id = my_id,
                 text = my_name,
                 item = new List<ItemTree>(),
                 parentId = my_par
               });
    }
}

そして、Where 句のある行でクラッシュします。クラッシュする理由は次のとおりです。ツリーにはアイテムのリストを持つアイテムが1つあり、クエリはツリーの最初のアイテムのみをチェックし、その子はチェックしません。

ツリーの深さ全体を検索してそこにアイテムを追加する方法は?

4

6 に答える 6

4

ツリー構造をリストにフラット化すると便利な場合があります。IEnumerable<ItemTree>ツリーのすべてのノードを含むがあれば、一部のロジックは簡単に表現できます。すべてのノードに親 ID がまだあるため、情報が失われることはありません。

これは自然に再帰的な問題です。再帰ラムダを使用して、次のようなものを試してください。

Func<ItemTree, IEnumerable<ItemTree>> flattener = null;
flattener = t => new[] { t }
                .Concat(t.item == null 
                        ? Enumerable.Empty<ItemTree>()
                        : t.item.SelectMany(child => flattener(child)));

このように再帰を作成するときは、最初に個別にFunc宣言し、null に設定する必要があることに注意してください。Func

イテレータ ブロック メソッドを使用してリストを平坦化することもできます。

public static IEnumerable<ItemTree> Flatten(ItemTree node)
{
    yield return node;
    if (node.item != null)
    {
         foreach(var child in node.item)
             foreach(var descendant in Flatten(child))
                 yield return descendant;
    }
}

いずれにせよ、ツリーが平坦化されると、平坦化されたリストに対して単純な Linq クエリを実行してノードを見つけることができます。

flattener(tree).Where(t => t.id == my_id);

次に、ツリーに追加するには、次のようにします。

var itemOfInterest = flattenedTree.Where(t => t.id == myId).Single();
itemOfInterest.item = itemOfInterest.item ?? new List<ItemTree>();
itemOfInterest.item.Add(myItemToAdd);

whereflattenedTreeは、2 つの平坦化戦略のいずれかを使用して生成されました。

itemまた、リストであるプロパティの素晴らしい名前ではないことにも注意してください。このようなプロパティは、ほとんどの場合、複数形 ( items) になります。また、プロパティは通常大文字で表記されます ( Items)。

于 2013-06-13T12:01:41.553 に答える
1

2013-06-13 12:14 の @AgentFire のソリューションは、

public static IEnumerable<T> SelectRecursively<T>(this IEnumerable<T> e,
                                                  Func<T, IEnumerable<T>> memberSelector)
{
    foreach (T item in e)
    {
        yield return item;

        IEnumerable<T> inner = memberSelector(item);

        if (inner != null)
        {
            foreach(T innerItem in inner.SelectRecursively(memberSelector))
            {
                yield return innerItem;
            }
        }
    }
}

内部アイテムを結果リストに取得します。

この素敵なアイデアをありがとう@AgentFire。

于 2016-05-10T15:53:04.303 に答える
0
  1. ItemTree にメソッド HasId を追加する必要があります
  2. このメソッドは、特定の ID の再帰的検索を実装し、true または false の回答を返す必要があります。
  3. 使用 (x => x.HasId(my_par))
于 2013-06-13T12:01:33.670 に答える
0

First()の代わりに使用していFirstOrDefault()ます。代わりに、次のようなことを行う必要があります。

var item = tree.item.Where(x => x.id == my_par)
           .Select(x => x.item)
           .FirstOrDefault();

if (item != null)
           .Add(new ItemTree 
           {
             id = my_id,
             text = my_name,
             item = new List<ItemTree>(),
             parentId = my_par
           });
于 2013-06-13T11:52:57.130 に答える