Linq选择出生日期范围和总和

时间:2015-04-07 13:51:21

标签: c# linq

我有一张如下表格

UserID UserName DateOfBirth
1      User1    1988-1-1
2      User2    1978-1-1
3      User3    1959-1-1
....
.....

我打算做的是查询类似于以下

的结果
Age range   Total User
16 - 25     10
26 - 35     20
36 - 45     15
46 - 55     16
56 - 65     30
> 70        40

我遇到的问题是我不知道如何将年龄范围分组如上。我只设法使用以下代码对每个用户的年龄进行分组

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() });

2 个答案:

答案 0 :(得分:0)

这样的事情应该有效:

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() });

顺便说一句,你不能只从当年减去出生年份来计算年龄。您必须创建一个函数来计算它。 Here you can find out how to calculate the age.

<强>更新

如果您想为年龄范围设置一个单独的组&#34;&gt; 65&#34;,那么你可以这样做:

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() });

你也可以为16岁以下的年龄做同样的事情。如果它变得更复杂,我建议创建一个单独的函数来获取Age Group字符串。

答案 1 :(得分:0)

如果您想使用linq进行操作,首先需要创建一些代表在特定年龄范围内的值。如果您使用的是SQL数据库,这可能会更好地作为存储过程。

目前,您正在按照您所知的年份执行分组。您需要第二个操作来计算每个范围内的匹配。使用您当前拥有的linq查询,然后执行以下操作(假设您在此类中有Dictionary<string,int> ageRanges,但您始终可以将其修改为在其他位置使用):

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
     }
}

这是我们的addToRanges方法:

private void addToRanges(string key, int value)
{
    if(ageRanges.ContainsKey(key))
    {
        ageRanges[key] += value;
    }
    else
    {
        ageRanges.Add(key, value);
    }
}

还有很多其他方法可以做到这一点,但这只是一个关于如何执行此操作的简单示例。这不一定是最有效的例子。拥有执行此计算的存储过程将是执行此计算的最佳/最高效方法,但此方法至少将向您展示如何使用已放在一起的linq查询来执行此操作。

这是一个更像linq的例子:

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()});

现在,这将使用IEnumerable而不是字典产生类似的结果。