开发者

How do I convert a recursive object to a Collection in C#?

I have a recursive object, a linked list really:

public class LinkedList 
{
    public string UniqueKey { get; set开发者_高级运维; }
    public LinkedList LinkedList { get; set; }
}

LinkedList will have some object graph that will eventually end in LinkedList.LinkedList == null.

I would like to take all the objects in the graph and put them into a LinkedList collection so that I can iterate over them. How do I do this in C#? I feel as if there's a really easy way of going about this using yield or Linq voodoo?


Something like this should work. If you have control over the class you can make it IEnumerable directly.

public class LinkedListEnumerable : IEnumerable<string>
{
    LinkedList list;
    public LinkedListEnumerable(LinkedList l)
    {
        this.list = l;
    }

    public IEnumerator<string> GetEnumerator()
    {
        LinkedList l = list;
        while(l != null)
        {
            yield return l.UniqueKey;
            l = l.Next;
        }
    }
}

Then you can iterate over LinkedListEnumerable with a for-each loop.


Is this what you want?

public class LinkedList
{
    public string UniqueKey { get; set; }
    public LinkedList LinkedList { get; set; }

    public IEnumerable<LinkedList> GetAllNodes()
    {
        if (LinkedList != null)
        {
            yield return LinkedList;
            foreach (var node in LinkedList.GetAllNodes())
                yield return node;
        }
    }
}


There are no nice LINQ methods in the standard .NET library to allow some elegant LINQ voodoo, but you can use Generate method from MoreLINQ project and write this:

Enumerable
  .Generate(list, l => l.LinkedList)
  .TakeWhile(l => l != null).Select(l => l.UniqueKey);

It uses Generate to create "infinite" list of all elements - it is not actually infinite, because it is generated lazily and we stop using it as soon as we find null value at the end (using TakeWhile). Then we use Select to return a sequence of values (instead of linked list nodes).

This is essentially a nice declarative way of expressing the while loop solution posted by Matthew (and it should have roughly similar performance).

EDIT The Generate method looks like this:

IEnumerable<T> Generate(T current, Func<T, T> generator) {
  while(true) { 
    yield return current;
    current = generator(current);
  }
}


I have a data structure in my project where an object can have a parent, and multiple children of itself. To get all the parents I can use this function:

    public static IEnumerable<TModel> EnumerateParents<TModel>(TModel model, Func<TModel, TModel> parentSelector)
    {
        var curr = model;
        while ((curr = parentSelector.Invoke(curr)) != null)
        {
            yield return curr;
        }
    }

Usage looks like this: _parents = ParentHelper.EnumerateParents(item, x => x.Parent).ToList();

I also made a function to enumerate all children which can be done with this function:

    public static IEnumerable<TModel> EnumerateChildren<TModel>(TModel root, Func<TModel, IEnumerable<TModel>> childSelector)
    {
        var children = childSelector.Invoke(root);
        if (children == null)
        {
            yield break;
        }

        foreach (var child in children)
        {
            yield return child;

            foreach (var grandChild in EnumerateChildren(child, childSelector))
            {
                yield return grandChild;
            }
        }
    }

which can be used like this: var children = ParentHelper.EnumerateChildren(item, x => x.Children)

The last one is not asked in the question, but posted it anyways for if someone might need it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜