【问题标题】:Linq Get Specified Children and their ParentsLinq 获取指定的孩子和他们的父母
【发布时间】:2020-05-07 13:19:09
【问题描述】:

我有两个类,父类和子类。我想让所有孩子符合某些标准的父母,例如所有父母及其女孩。我想使用Linq 来做到这一点。我使用了以下Linq 查询,它返回所有有女孩的父母,但是孩子列表也包含男孩。我只想在List<Parent> parentsAndFemaleChildren 有父母和他们的女儿。请参阅下面的Linq 查询:

List<Parent> parentsAndFemaleChildren = Parents
    .Where(p => p.Children.Any((c => c.Gender == "Female")))
    .ToList();

填充数据的代码如下所示。

public class Parent
{
    public int ParentId {get;set;}
    public string ParentName {get;set;}
    public List<Child> Children {get;set;}
}
public class Child
{
    public int ChildId {get;set;}
    public string ChildName {get;set;}
    public string Gender {get;set;}
    public int ParentId {get;set;}
}

我已按以下方式填充数据。

public static void Main()
    {
        List<Parent> Parents = new List<Parent>();

        Parent p1 = new Parent();
        p1.ParentId = 1;
        p1.ParentName = "Parent 1";
        Parents.Add(p1);    


        Child p1C1 = new Child();
        p1C1.ChildId = 1;
        p1C1.ChildName = "Parent 1 Child 1";
        p1C1.Gender = "Male";
        p1C1.ParentId = 1;

        p1.Children = new List<Child>();

        p1.Children.Add(p1C1);

        Child p1C2 = new Child();
        p1C2.ChildId = 2;
        p1C2.ChildName = "Parent 1 Child 2";
        p1C2.Gender = "Female";
        p1C2.ParentId = 1;

        p1.Children.Add(p1C2);

        Parent p2 = new Parent();
        p2.ParentId = 2;
        p2.ParentName = "Parent 2";
        Parents.Add(p2);

        Child p2C1 = new Child();
        p2C1.ChildId = 3;
        p2C1.ChildName = "Parent 2 Child 1";
        p2C1.Gender = "Female";
        p2C1.ParentId = 2;

        p2.Children = new List<Child>();

        p2.Children.Add(p2C1);

        Child p2C2 = new Child();
        p2C2.ChildId = 4;
        p2C2.ChildName = "Parent 2 Child 2";
        p2C2.Gender = "Male";
        p2C2.ParentId = 2;

        p2.Children.Add(p2C2);

        Parent p3 = new Parent();
        p3.ParentId = 3;
        p3.ParentName = "Parent 3";
        Parents.Add(p3);

        Child p3C1 = new Child();
        p3C1.ChildId = 5;
        p3C1.ChildName = "Parent 3 Child 1";
        p3C1.Gender = "Male";
        p3C1.ParentId = 3;

        p3.Children = new List<Child>();

        p3.Children.Add(p3C1);


        DisplayFemaleChildrenAndParents(Parents);
    }

    public static void DisplayFemaleChildrenAndParents(List<Parent> Parents)
    {
        List<Parent> parentsAndFemaleChildren = Parents.Where(p => p.Children.Any((c => c.Gender == "Female"))).ToList();
        Console.WriteLine("\nShould Display Parents and their Female children details ONLY\n");
        foreach(Parent p in parentsAndFemaleChildren)
        {       
            Console.WriteLine("***********");           
            foreach(Child c in p.Children)
            {               
                Console.WriteLine(p.ParentName + " - " + c.ChildName + " - " + c.Gender);
            }
            Console.WriteLine("***********");
        }
    }

可以通过 dotnet fiddle click here 查看和运行完整代码。

【问题讨论】:

  • 我喜欢带有可行样本的问题。

标签: c# linq


【解决方案1】:

在最新版本的语言中,您可以玩 valutuples:

var parentsAndFemaleChildren = Parents
    .Select(p=> (parent: p, femaleChildren: p.Children.Where(c => c.Gender == "Female").ToList()))
    .Where(p => p.femaleChildren.Any())
    .ToList();

及打印功能:

    foreach(var (p, children) in parentsAndFemaleChildren)
    {       
        Console.WriteLine("***********");           
        foreach(Child c in children)
        {               
            Console.WriteLine(p.ParentName + " - " + c.ChildName + " - " + c.Gender);
        }
        Console.WriteLine("***********");
    }

【讨论】:

  • 在 Linq 中,我可以说匿名类型被使用得更多,所以即使元组也可以使用,我也没有。现在我想知道什么会更好..
  • 你可以对匿名类型做同样的事情。至于什么面糊我更喜欢 valuetuples 因为他们应该分配更少。
  • 您认为它们与 linq2sql 的行为是否相同?
  • 实际上从未尝试过。但是,如果您没有在物化结果中使用,我认为它们之间没有区别(如果底层提供者支持元组)并且可以坚持使用匿名类型。
  • @learner 那么你需要创建新的Parent 对象,它只包含女性孩子。比如“.Select(p => new Parent{Id = p.Id, Name = p.Name, Children = p.Children.Where(....).ToList()})”
【解决方案2】:

这可行:https://dotnetfiddle.net/ckwCs1

    public static void DisplayFemaleChildrenAndParents(List<Parent> Parents)
    {
        List<Parent> parentsAndFemaleChildren = Parents.Where(p => p.Children.Any((c => c.Gender == "Female"))).ToList();
        Console.WriteLine("\nShould Display Parents and their Female children details ONLY\n");
        foreach(Parent p in parentsAndFemaleChildren)
        {       
            Console.WriteLine("***********");           
            foreach(Child c in p.Children.Where(c=>c.Gender == "Female"))
            {               
                Console.WriteLine(p.ParentName + " - " + c.ChildName + " - " + c.Gender);
            }
            Console.WriteLine("***********");
        }
    }
***********
Parent 1 - Parent 1 Child 1 - Male
Parent 1 - Parent 1 Child 2 - Female
***********
***********
Parent 2 - Parent 2 Child 1 - Female
Parent 2 - Parent 2 Child 2 - Male
***********
***********
Parent 3 - Parent 3 Child 1 - Male
***********

Should Display Parents and their Female children details ONLY

***********
Parent 1 - Parent 1 Child 2 - Female
***********
***********
Parent 2 - Parent 2 Child 1 - Female
***********

您首先获取有一些女性孩子的父母,然后过滤掉所有男性孩子,因此您只显示女性。

编辑:

另一种风味:

https://dotnetfiddle.net/sFObju

    public static void DisplayFemaleChildrenAndParents(List<Parent> Parents)
    {
        List<Parent> parentsAndFemaleChildren = Parents.Where(p => p.Children.Any((c => c.Gender == "Female"))).ToList();
        Console.WriteLine("\nShould Display Parents and their Female children details ONLY\n");
        foreach(Parent p in parentsAndFemaleChildren)
        {       
            Console.WriteLine("***********");           
            foreach(Child c in p.Children.Where(c=>c.Gender == "Female"))
            {               
                Console.WriteLine(p.ParentName + " - " + c.ChildName + " - " + c.Gender);
            }
            Console.WriteLine("***********");
        }

                    Console.WriteLine("\n\n ***********   v2 ***********   \n\n");


        // alternative
        var parentsWithFemales = Parents.Select(p => new {p, FemaleChildren = p.Children.Where(a => a.Gender == "Female")})
                                        // Filter out parents without female children
                                        .Where(x => x.FemaleChildren.Any());
        foreach(var pc in parentsWithFemales)
        {
            Console.WriteLine(pc.p.ParentName + "\tfemale children:");
            foreach(var c in pc.FemaleChildren)
                Console.WriteLine("\t"+c.ChildName + ", Gender: " + c.Gender);
        }

    }
***********
Parent 1 - Parent 1 Child 1 - Male
Parent 1 - Parent 1 Child 2 - Female
***********
***********
Parent 2 - Parent 2 Child 1 - Female
Parent 2 - Parent 2 Child 2 - Male
***********
***********
Parent 3 - Parent 3 Child 1 - Male
***********

Should Display Parents and their Female children details ONLY

***********
Parent 1 - Parent 1 Child 2 - Female
***********
***********
Parent 2 - Parent 2 Child 1 - Female
***********


 ***********   v2 ***********   


Parent 1    female children:
    Parent 1 Child 2, Gender: Female
Parent 2    female children:
    Parent 2 Child 1, Gender: Female

编辑2:

https://dotnetfiddle.net/N8K0AF

        var parentsWithFemales = Parents.Select(p => new Parent(){ParentId = p.ParentId, ParentName = p.ParentName, Children = p.Children.Where(a => a.Gender == "Female").ToList()})
                                        // Filter out parents without female children
                                        .Where(x => x.Children.Any());
        foreach(var pc in parentsWithFemales)
        {
            Console.WriteLine(pc.ParentName + "\tfemale children:");
            foreach(var c in pc.Children)
                Console.WriteLine("\t"+c.ChildName + ", Gender: " + c.Gender);
        }

输出同上:

Parent 1    female children:
    Parent 1 Child 2, Gender: Female
Parent 2    female children:
    Parent 2 Child 1, Gender: Female

【讨论】:

  • foreach 循环仅用于演示目的。我希望 List parentsAndFemaleChildren 变量包含至少有一名女性的父母,而 parentsAndFemaleChildren.Children 仅包含女性孩子,而不使用匿名类型。版本 1 使用 foreach 循环,版本 2 使用匿名类型。抱歉,我应该更清楚地了解匿名类型,但我认为它可以用以下短语来理解:我只想在 List parentsAndFemaleChildren 中有父母及其女性孩子。但我应该更清楚。
  • @learner 编辑了答案以包括创建一个新的父对象。
【解决方案3】:

如果您需要过滤只有女性孩子的父母,那么您应该使用ALLlinq 方法。

MSDN says about .All method:

判断一个序列的所有元素是否满足一个条件。

List<Parent> parentsAndFemaleChildren = Parents
    .Where(p => p.Children.All((c => c.Gender == "Female"))).ToList();

如果你想得到至少有一个女性孩子的父母并且只选择女性孩子,那么你可以使用select方法和Where

List<Parent> parentsAndFemaleChildren = Parents
    .Where(p => p.Children.Any((c => c.Gender == "Female")))
    .Select(s => new Parent { ParentId = s.ParentId, ParentName = s.ParentName, 
        Children = s.Children.Where(ch => ch.Gender == "Female").ToList()}).ToList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 2013-06-04
    • 2018-11-20
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多