Ryan L
Ryan L

Reputation: 31

LinQ query that counts the number of elements in a list of objects in another list of objects

I have this kind of structure :

At first, there is a list of families.

EDIT: each family contains a group of person

EDIT: each person is defined by a gender

I have to count how many of those persons are males, and how many are females, so here is what I tried:

int boys = ListOfFams.Where(f => f.persons.Where(p => p.gender == gender.male)).Count();

It seems I cannot just ask for the number of males or females because I need a condition to put after the first "where", but then, I don't know how I should build my request.

Do you guys have any idea ?

Thank you for your time

Edit again: Thank you all for your answers, and sorry for the late edit on the question regarding the group of persons etc.

Upvotes: 1

Views: 1479

Answers (3)

Flater
Flater

Reputation: 13783

The other answers are also correct, but there is a third way.

Essentially, you're not interested in the families, but the people in those families. Rather than performing a nested count (once per family) which you then sum, you can also:

  1. Convert the list of families into a list of the people in those families

IEnumerable<Person> allPeopleInTheseFamilies = ListOfFams.SelectMany(fam => fam.persons);
  1. Count how many males there are in that list.

int totalMales = allPeopleInTheseFamilies.Count(person => person.gender == gender.male);

This can of course be chained as well:

int totalMales = ListOfFams
                     .SelectMany(fam => fam.persons)
                     .Count(person => person.gender == gender.male);

If you're worried about nullability, you can add in extra null checks (though I would generally advise to avoid having nulls in the list in the first place)

int totalMales = ListOfFams
                     .Where(fam => fam != null && fam.persons != null)
                     .SelectMany(fam => fam.persons)
                     .Count(person => person != null && person.gender == gender.male);

Upvotes: 1

Cato
Cato

Reputation: 3701

if you select each family, then return the count of males in it, you would get an enumerable of counts - e.g {0,1,0,3,2,1} - you can then simply Sum those counts

  ListOfFams.Select(f => f.persons.Where(p => p.gender == gender.male).Count()).Sum();

//to reject nulls

ListOfFams.
    Where(f => f != null && f.persons != null).
    Select(f => f.persons.
    Where(p => p != null && p.gender == gender.male).
    Count()).
    Sum();

Upvotes: 1

Ren&#233; Vogt
Ren&#233; Vogt

Reputation: 43886

You can simply use LINQ's Count() and Sum() to achieve that:

int boy = ListOfFams.Sum(f => f.persons.Count(p => p.gender == gender.male));

This counts the male persons per family and sums up the results.


If you expect any of those collections to contain null values, you need to protect against that like this:

int boy = ListOfFams.Sum(f => f?.persons?.Count(p => p?.gender == gender.male) ?? 0);

Now this only counts persons that are not null and male, and only persons of families that are not null and whose persons list is not null.
If a family or a persons collection is null, they are counted as 0.

Upvotes: 3

Related Questions