Reputation: 541
I have two classess Parent and Child. I would like to get all parents whose children meet some criteria e.g all parents and their female children. I would like to do this using Linq
. I have used the following Linq
query and it returns all parents with female children, however the children list also contains male children. I would only like to have parent and their female children in List<Parent> parentsAndFemaleChildren
. Please see the Linq
query below:
List<Parent> parentsAndFemaleChildren = Parents
.Where(p => p.Children.Any((c => c.Gender == "Female")))
.ToList();
The code for populating data is shown below.
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;}
}
I have populated the data as per below.
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("***********");
}
}
The full code can be seen and run via dotnet fiddle click here.
Upvotes: 4
Views: 801
Reputation: 7660
This would work: 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
***********
You first fetch parents that have some female children at all, and then you filter out any male children, so you only display females.
EDIT:
Another flavor:
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
Edit2:
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);
}
Outputs the same as above:
Parent 1 female children:
Parent 1 Child 2, Gender: Female
Parent 2 female children:
Parent 2 Child 1, Gender: Female
Upvotes: 2
Reputation: 38209
If you need to filter parents who have ONLY female children, then you should use ALL
linq method.
Determines whether all elements of a sequence satisfy a condition.
List<Parent> parentsAndFemaleChildren = Parents
.Where(p => p.Children.All((c => c.Gender == "Female"))).ToList();
If you want to get parents who have at least one children with female gender and select just female children, then you can use select
method with 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();
Upvotes: 1
Reputation: 143453
In latest version of language you can play with valutuples:
var parentsAndFemaleChildren = Parents
.Select(p=> (parent: p, femaleChildren: p.Children.Where(c => c.Gender == "Female").ToList()))
.Where(p => p.femaleChildren.Any())
.ToList();
And print function:
foreach(var (p, children) in parentsAndFemaleChildren)
{
Console.WriteLine("***********");
foreach(Child c in children)
{
Console.WriteLine(p.ParentName + " - " + c.ChildName + " - " + c.Gender);
}
Console.WriteLine("***********");
}
Upvotes: 2