简体   繁体   English

如何在 C# 中将递归对象转换为集合?

[英]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. LinkedList 将有一些最终以 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.我想获取图中的所有对象并将它们放入 LinkedList 集合中,以便我可以遍历它们。 How do I do this in C#?我如何在 C# 中做到这一点? I feel as if there's a really easy way of going about this using yield or Linq voodoo?我觉得好像有一种非常简单的方法可以使用 yield 或 Linq voodoo 来解决这个问题?

Something like this should work.像这样的东西应该工作。 If you have control over the class you can make it IEnumerable directly.如果您可以控制该类,则可以直接将其设置为IEnumerable

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.然后,您可以使用 for-each 循环遍历LinkedListEnumerable

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:标准 .NET 库中没有很好的 LINQ 方法来允许一些优雅的 LINQ 巫术,但您可以使用MoreLINQ项目中的Generate方法并编写以下代码:

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 ).它使用Generate来创建所有元素的“无限”列表——它实际上并不是无限的,因为它是惰性生成的,一旦我们在最后找到null值(使用TakeWhile )就停止使用它。 Then we use Select to return a sequence of values (instead of linked list nodes).然后我们使用Select返回一个值序列(而不是链表节点)。

This is essentially a nice declarative way of expressing the while loop solution posted by Matthew (and it should have roughly similar performance).这本质上是表达 Matthew 发布的while循环解决方案的一种很好的声明方式(它应该具有大致相似的性能)。

EDIT The Generate method looks like this:编辑Generate方法如下所示:

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();用法如下所示: _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)可以这样使用: 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.问题中没有问最后一个问题,但无论如何都会发布它以防有人需要它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM