使用linq(IGrouping)按值范围对项目进行分组

时间:2014-10-10 17:39:19

标签: c# linq grouping

说我有一个Person

列表
public class Person
{
    public int Age { get; set; }
    public string Name { get; set; }
}
  1. 如何按动态范围分组? (例如,从最年轻的人开始,我想按5的范围分组,所以如果最年轻的人是12,那么这些组将是12-17,18-23 ....)

  2. 如何确定Key接口的IGrouping? (例如,将每个组的Key设置为该组中的平均年龄)

2 个答案:

答案 0 :(得分:3)

要获得分组键,您可以创建一个函数:

String GetAgeInterval(Int32 age, Int32 minimumAge, Int32 intervalSize) {
  var group = (age - minimumAge)/intervalSize;
  var startAge = group*intervalSize + minimumAge;
  var endAge = startAge + intervalSize - 1;
  return String.Format("{0}-{1}", startAge, endAge);
}

假设最小年龄为12且间隔大小为5,那么对于年龄介于12和16(含)之间的年龄,函数将返回字符串12-16,年龄介于17和21之间(包括),函数将返回字符串17-21等。或者您可以使用间隔大小为6来获取间隔12-17,18-23等。

然后您可以创建组:

var minimumAge = persons.Min(person => person.Age);
var personsByAgeIntervals = persons
  .GroupBy(person => GetAgeInterval(person.Age, minimumAge, 5));

要获得每组的平均年龄,您可以执行以下操作:

var groups = personsByAgeIntervals.Select(
  grouping => new {
    AgeInterval = grouping.Key,
    AverageAge = grouping.Average(person => person.Age),
    Persons = grouping.ToList()
  }
);

这将创建一个由匿名类型表示的组序列,其中包含属性AgeIntervalAverageAgePersons

答案 1 :(得分:1)

使用Linq而不是IGrouping(我从来没有使用过这个界面,所以我没想到帮助你成为最好的开始时间)。我添加了一个配置类来设置最小/最大年龄以及基本描述符。

    public class GroupConfiguration {
        public int MinimumAge { get; set; }
        public int MaximumAge { get; set; }
        public string Description { get; set; }
    }

我创建了一个Person(人员)列表,并用一些示例记录填充它。

        List<Person> people = new List<Person>() {
            new Person(12, "Joe"),
            new Person(17, "Bob"),
            new Person(21, "Sally"),
            new Person(15, "Jim")
        };

然后我创建了一个GroupConfiguration(配置)列表,并用3个逻辑对我的记录填充它。

        List<GroupConfiguration> configurations = new List<GroupConfiguration>() {
            new GroupConfiguration() {MinimumAge = 0, MaximumAge=17, Description="Minors"},
            new GroupConfiguration() {MinimumAge = 18, MaximumAge=20, Description="Adult-No Alcohol"},
            new GroupConfiguration() {MinimumAge = 21, MaximumAge=999, Description="Adult-Alcohol"},
        };

然后我将它们加载到字典中,以维护配置与匹配该配置的结果之间的关系。这使用Linq查找与MinimumAge&lt; = age&lt; = MaximumAge匹配的人员的记录。如果有MinimumAge和Maximum Age重叠,这将允许某人被置于多个结果中。

        Dictionary<GroupConfiguration, IEnumerable<Person>> groupingDictionary = configurations.ToDictionary(groupConfiguration => groupConfiguration, groupConfiguration
            => people.Where(x => x.Age >= groupConfiguration.MinimumAge && x.Age <= groupConfiguration.MaximumAge));

在控制台程序中抛出此内容,我验证了Minors组中有3个人,成人 - 无酒精组中有0人,成人 - 酒精组中有1人。

        foreach (var kvp in groupingDictionary) {
            Console.WriteLine(kvp.Key.Description + " " + kvp.Value.Count());
        }
        Console.ReadLine();