Reputation: 3221
I have a table like the following
UserID UserName DateOfBirth
1 User1 1988-1-1
2 User2 1978-1-1
3 User3 1959-1-1
....
.....
What I intend to do is to query a result similar to following
Age range Total User
16 - 25 10
26 - 35 20
36 - 45 15
46 - 55 16
56 - 65 30
> 70 40
The problem i am having is i do not know how to group the age range as above. I only manage to group the age of each individual user using following code
db.User
.Where(p => p.DateOfBirth != null)
.GroupBy(p => p.DateOfBirth.Value.Year)
.Select(g => new { Age = DateTime.Now.Year - g.Key, Count = g.Count() });
Upvotes: 1
Views: 2078
Reputation: 9155
Something like this should work:
db.User.Where(p => p.DateOfBirth != null).ToList()
.Select(p => new { UserId = p.UserId, Age = DateTime.Now.Year - p.DateOfBirth.Value.Year })
.GroupBy(p => (int)((p.Age - 16) / 10))
.Select(g => new { AgeGroup = string.Format("{0} - {1}", g.Key * 10 + 16, g.Key * 10 + 25), Count = g.Count() });
By the way, you can't just subtract the birth year from the current year to calculate the age. You'll have to create a function to calculate it. Here you can find out how to calculate the age.
UPDATE:
If you want to have a separate group for age range "> 65", then you can do it like this:
db.User.Where(p => p.DateOfBirth != null).ToList()
.Select(p => new { UserId = p.UserId, Age = DateTime.Now.Year - p.DateOfBirth.Value.Year })
.GroupBy(p => p.Age > 65 ? 5 : (int)((p.Age - 16) / 10))
.Select(g => new { AgeGroup = g.Key == 5 ? "> 65" : string.Format("{0} - {1}", g.Key * 10 + 16, g.Key * 10 + 25), Count = g.Count() });
You can do the same thing for ages below 16 too. If it gets more complicated, I recommend creating a separate function to get the Age Group string.
Upvotes: 1
Reputation: 7097
You first would need to create some sort of value that would represent being within a certain age-range if you want to do it using linq. This might work better as a Stored Procedure though if you're using a SQL database.
Currently, you are performing your grouping on the year as you know. You'd need a second operation to count up the matches within each range. Use the linq query that you currently have and then do the following (this assumes you have Dictionary<string,int> ageRanges
within this class, but you can always modify this to have it elsewhere):
var query = /*LINQ QUERY HERE*/;
foreach(var g in query)
{
int ranges = g.Age / 5; //range in example is every 10 years starting at 16
switch(ranges)
{
case 0: //0 -5
case 1: //5 - 9
case 2: //10-15
continue; //we don't care about these values
case 3: //16-20
case 4: //21-25
addToRanges("16-25",g.Count);
break;
... //etc you get the idea
}
}
Here's our addToRanges method:
private void addToRanges(string key, int value)
{
if(ageRanges.ContainsKey(key))
{
ageRanges[key] += value;
}
else
{
ageRanges.Add(key, value);
}
}
There are lots of other ways to do this, but this is just some simple example on how you can perform this operation. This is not necessarily the most performant example. Having a Stored Procedure that performs this calculation would be the best/most performant way to do this, but this method will at least show you how to do it with the linq query that you already put together.
Here's a more linq like example:
db.User
.Where(p => p.DateOfBirth != null)
.GroupBy(p => p.DateOfBirth.Value.Year)
.Select(g =>
{
int age = DateTime.Now.Year - g.Key;
int range = (age / 5) - 3; //Assumes that everything is at least age > 15
if(range % 2 == 1)
range -= 1; //to make sure we group 10s not 5s
return new { Age = age, Count = g.Count(), Range = range }
})
.GroupBy(a => g.Range)
.Select(g => new {RangeValue = g.Range, Count = g.Count()});
Now this will produce a similar result with an IEnumerable instead of a dictionary.
Upvotes: 0