使用 LINQ 展平列表列表以获取父/子列表

Posted

技术标签:

【中文标题】使用 LINQ 展平列表列表以获取父/子列表【英文标题】:Flattening a list of lists, using LINQ, to get a list of parent/child 【发布时间】:2021-07-07 16:48:43 【问题描述】:

我正在尝试展平相同 <Person> 类型的父/子列表。这里的困难是我会 喜欢将父母和孩子合并到一个平面 <Person> 列表中。

我得到的最接近的是:

class Person

    public string Name  get; set; 
    public List<Person> Children  get; set; 


List<Person> parents = new List<Person>() 
    new Person() 
        Name = "parentA",
        Children = new List<Person>() 
            new Person()  Name = "childB" ,
            new Person()  Name = "childC" 
        
    ,
    new Person() 
        Name = "parentD",
        Children = new List<Person>() 
            new Person()  Name = "childE" ,
            new Person()  Name = "childF" 
        
    
;

var result = parents.SelectMany(parent => parent.Children
    .Select(child => parent.Name + ", " + child.Name));

这给了我结果:

parentA, childB
parentA, childC
parentD, childE
parentD, childF

我正在寻找的是获得&lt;Person&gt; 列表,例如:

parentA
childB
childC
parentD
childE
childF

保持顺序,否则性能并不重要。但我希望,如果可能,坚持纯 LINQ 和 LINQ 方法。

谢谢,

【问题讨论】:

***.com/questions/11830174/… SelectMany(parent =&gt; parent.Children.Append(parent).Select(x =&gt; x.Name)) 如果你只需要深入一层? 如果您想保留先父后子的顺序,就像您的问题一样,您可以使用Prepend 而不是Appendparents.SelectMany(p =&gt; p.Children.Prepend(p)); 你们明白了,这正是我要找的。谢谢!我可以将评论标记为解决方案吗? 【参考方案1】:

如果你想要一层深度,我建议将ConcatSelectMany 结合使用:

 var parents = ...

 var result = parents
   .SelectMany(person => new Person[] person.Concat(person.Children))
   .Select(person => person.Name); // if we want just names

 // Let's have a look
 Console.WriteLine(string.Join(Environment.NewLine, result));

【讨论】:

Dmitry,你的回答也很有帮助,因为在代码中的某个地方, .Prepend() 会因为某种原因而不是 ObservableCollection 上的方法(仍然没有想到那个还没有)。然而,这完美无缺。谢谢。【参考方案2】:
var persons = new List<Person>();
parents.ForEach(p => 
        persons.Add(p); 
        persons.AddRange(p.Children);
    
);


foreach(var person in persons)
        Console.WriteLine(person.Name);
    

我知道这不是一行,但我想这就是你要找的。​​p>

【讨论】:

【参考方案3】:

尝试以下课程:

    class Person
    
        public static DataTable dt  get;set;

        public string Name  get; set; 
        public List<Person> Children  get; set; 

        public void GetTree(Person root)
        
            DataTable dt = new DataTable();
            dt.Columns.Add("Parent Name", typeof(string));
            dt.Columns.Add("Child Name", typeof(string));
            GetTreeRecursive(root, "");

        
        public void GetTreeRecursive(Person person, string parentName)
        
            foreach(Person child in person.Children)
            
                dt.Rows.Add(parentName, child.Name);
                if (child.Children != null)
                
                    GetTreeRecursive(child, child.Name);
                
            
        
    

【讨论】:

【参考方案4】:

感谢我最初帖子中的 cmets,我能够得到我想要的东西。

该解决方案仅适用于一个级别,这正是我所需要的。不过,它可以递归更深入:

var result = parents.SelectMany(person => person.Children
        .Prepend(person))
    .Select(p => p.Name);

给了我预期的结果:

parentA 
childB 
childC 
parentD 
childE 
childF 

这让我可以使用展平列表中的所有对象,包括父对象。

【讨论】:

以上是关于使用 LINQ 展平列表列表以获取父/子列表的主要内容,如果未能解决你的问题,请参考以下文章

在捕获索引时使用 LINQ 展平列表

结合列表中实体的两个属性并将其与 Linq 展平

LINQ:在运行时访问子列表

Thinkcmf子栏目获取父级栏目所有子栏目列表

使用LINQ获取List列表中的某个字段值

如何获取 linq `ForEach` 语句以返回有关为每个列表对象进行的方法调用的数据?