【问题标题】:linq objects groupinglinq 对象分组
【发布时间】:2011-05-10 11:26:33
【问题描述】:

我有人员对象,而人员有属性组,使他们属于不同的组。 我想获取 List 并将其放入一个对象 GrouppedPeople 中,其中将有 List coll。一个 coll 元素只包含属于同一组的人。

如果我有 3 个人:

List<People>(){new People{Name="Test", Group = "Group1"},
               new People{Name="SameGroup", Group = "Group1"},
               new People{Name="Other", Group = "OtherGroup"}}

我需要收集 2 个 GrouppedPeople。第一个将包含 Test 和 SameGroup,第二个将包含 Other(按 Group 属性分组)。我正在尝试使用 linq 来做到这一点。

我需要结果为 List 类型。 GrouppedPeople 是一个类,它只有一个 List 类型的属性,并且所有人员都来自同一个组。

我想出了这样的东西:

from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select g;

它工作正常,但结果对象不是强类型的。我希望得到 List 作为结果。有没有办法从那个匿名对象类型中获取它?还有其他方法可以使用 linq 获得这一切并保持强类型吗?

【问题讨论】:

  • 你不会失去强类型。匿名类型与名义类型一样强类型。他们只是没有名字,仅此而已。
  • 你想要什么类型的列表?据我所知,您的现有代码中必须有 IEnumerable>。
  • 我想要列表。 GrouppedPeople 是一个包含 List. 的对象

标签: linq group-by linq-to-objects


【解决方案1】:

这将返回匿名类型对象列表:

var result = (from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select g).ToList();

但是如果你想返回特定类型的对象,你应该创建具有所需属性的新类:

public class MateGroup
{
 public string Name {get;set;}
}

var result = (from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select new MateGroup(){ Name =  g.<field_name>}).ToList();

更新:

根据您的评论,请尝试以下操作:

var result = (from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select new GrouppedPeople(){ People =  g.ToList()}).ToList();

【讨论】:

  • 我想要列表。 GrouppedPeople 是一个包含 List 的对象。我怎样才能得到它?
【解决方案2】:

你会得到一个IEnumerable&lt;IGrouping&lt;string, People&gt;&gt;IGrouping&lt;TKey, TElement&gt; 接口有一个 Key 包含您分组的值(在您的情况下,一个字符串包含来自 People 对象中的 Group 属性的值),您可以枚举它以获取项目所属组:

IEnumerable<IGrouping<string, People>> result = from oneGroup in mates
                group oneGroup by oneGroup.Group into g
                select g;

foreach (IGrouping<string, People> grouping in result)
{
    Console.WriteLine("Group: {0}", grouping.Key);
    foreach (People people in grouping)
    {
        Console.WriteLine(" - {0}", people.Name);
    }
}

结果输出(基于您的示例数据):

Group: Group1
 - Test
 - SameGroup
Group: OtherGroup
 - Other

【讨论】:

    【解决方案3】:

    我更喜欢使用通用 C# 语法来编写 LINQ 查询,它比简单的查询形式更清晰。

    您可以使用结果选择器将分组结果解析为类型化对象。

    var resultList = mates
        .GroupBy(p => p.Group, (g, p) => new B() { Group = g, People = p.ToList() })
        .ToList();
    

    完整的测试控制台应用代码:

    class People
    {
        public string Name;
        public string Group;
    }
    
    class GroupedPeople
    {
        public string Group;
        public List<People> People;
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var mates = new List<People>()
            {
                new People{Name="Test", Group = "Group1"},
                new People{Name="SameGroup", Group = "Group1"},
                new People{Name="Other", Group = "OtherGroup"}
            };
    
            var resultList = mates
                .GroupBy(p => p.Group, (g, p) => new GroupedPeople() { Group = g, People = p.ToList() })
                .ToList();
        }
    }
    

    GroupBy 调用需要两个参数:

    1. p =&gt; p.Group - 用于返回分组键的 lambda(匿名方法)

    2. (g, p) => new GroupedPeople() { Group = g, People = p.ToList() }

      该 lambda 用于基于组参数创建 GroupedPeople 对象,第一个参数是第一个 lambda 选择的分组键,第二个参数是与当前组相关的项目的枚举。

    【讨论】:

    • Viacheslav,您能详细解释一下吗?我尝试使用此代码,但它对我不起作用。什么是“g”?我在 VS 中收到以下错误:无法将 lambda 表达式转换为类型 IEqualityComparer 因为它不是委托类型。
    • 您需要更多详细信息吗?我不知道您是否需要有关 lambda 或扩展的信息?
    • 完美运行,非常感谢。我希望我可以将 2 个答案标记为答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 2013-01-06
    • 2013-09-05
    相关资源
    最近更新 更多