【问题标题】:How do I convert a recursive object to a Collection in C#?如何在 C# 中将递归对象转换为集合?
【发布时间】:2010-07-18 01:18:07
【问题描述】:

我有一个递归对象,真的是一个链表:

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

LinkedList 会有一些最终以 LinkedList.LinkedList == null 结尾的对象图。

我想获取图中的所有对象并将它们放入 LinkedList 集合中,以便我可以迭代它们。我如何在 C# 中做到这一点?我觉得好像有一种非常简单的方法可以使用 yield 或 Linq voodoo 来解决这个问题?

【问题讨论】:

    标签: c# linq generics collections


    【解决方案1】:

    这样的事情应该可以工作。如果您可以控制该课程,您可以直接将其设为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;
            }
        }
    }
    

    然后您可以使用 for-each 循环遍历 LinkedListEnumerable

    【讨论】:

    • 是的,没错。除非您逐字逐句回答问题,否则它应该是 yield return l 而不是 yield return l.UniqueKey 对吗?尽管如此,OP 应该很容易弄清楚那部分。
    【解决方案2】:

    这是你想要的吗?

    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;
            }
        }
    }
    

    【讨论】:

    • 这不是很有效。对于一个包含 100 个项目的列表,您将创建 100 个枚举器,最后一个项目必须通过所有这些枚举器才能返回给调用者。
    【解决方案3】:

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

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

    它使用Generate 来创建所有元素的“无限”列表——它实际上并不是无限的,因为它是延迟生成的,一旦我们在末尾找到null 值就停止使用它(使用@987654326 @)。然后我们使用Select返回一个值序列(而不是链表节点)。

    这本质上是表达 Matthew 发布的 while 循环解决方案的一种很好的声明方式(它应该具有大致相似的性能)。

    EDITGenerate 方法如下所示:

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

    【讨论】:

    • 这很棒,但不幸的是我无法将任何其他库添加到项目中。不过,我会在未来的产品上使用它!
    • @Geoffrey:您可以将Generate 方法添加到您的项目中(只需3行代码)。
    猜你喜欢
    • 1970-01-01
    • 2011-01-20
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 2017-10-24
    • 2015-09-24
    相关资源
    最近更新 更多