C# LINQ列表中的多个分组依据<;T>;然后转换为列表<;T>;

C# LINQ列表中的多个分组依据<;T>;然后转换为列表<;T>;,c#,.net,linq,C#,.net,Linq,我有以下课程 public class Person { public string ID {get; set;} public string Name {get; set;} public string District {get; set;} public string Level {get; set;} } 然后,在我的函数中,我正在编写一个LINQ,将一个人员列表按地区、然后按级别分组到一个相同类型(人员)的新列表中 我想以一种不使用var(使其成为匿名类型)和new的

我有以下课程

public class Person
{
  public string ID {get; set;}
  public string Name {get; set;}
  public string District {get; set;}
  public string Level {get; set;}
}
然后,在我的函数中,我正在编写一个LINQ,将一个人员列表按地区、然后按级别分组到一个相同类型(人员)的新列表中

我想以一种不使用var(使其成为匿名类型)和new的方式编写它:

差不多

List<Person> persons; \\this already has values
List<Person> grpByP = persons
  .GroupBy()
  .ToList<Person>(); \\ Linq query to group persons list by District and Level
列出人员\\这已经有了价值
列表grpByP=人
.GroupBy()
.ToList();\ \Linq按地区和级别查询分组人员列表
我只是不知道如何编写grpByP LINQ查询

更新:我希望在grpByP变量的值中保留ID和名称,因为使用匿名类型将只包括地区和级别

任何帮助都将不胜感激。

已经解释了如何使用
GroupBy
。我将讨论第二部分:“转换为
列表
”和“不使用
var

首先,关于将
GroupBy
的结果转换为
List
:您不能这样做。
GroupBy
操作的结果是一个
IEnumerable
(假设您是按
string
属性分组的),它本身就是
IEnumerable
IEnumerable
;每个内部
IEnumerable
对应于找到的每个键,您可以使用
key
属性检查每种情况下的键:

var grouped = persons.GroupBy(p => p.District);
foreach(var group in grouped) 
{
    Console.WriteLine($"People in disctrict {group.Key}:");
    foreach(var person in group)
    {
        Console.WriteLine(person.Name);
    }
}
你可以回去查看未分组人员的完整列表,但我认为这没有多大意义:

var ungrouped = grouped.SelectMany(g => g).ToList<Person>();
var ungroup=group.SelectMany(g=>g.ToList();
关于不使用
var
:您当然可以将变量定义为
IEnumerable
,但我看不出这样做有什么好处

编辑:如果其他答案表明您实际上想做的是对数据进行排序,而不是对其进行分组,则所有这些都不适用

根据您的评论编辑:“我希望在grpByP变量的值中保留ID和名称,因为使用匿名类型将只包括地区和级别”-
GroupBy
不会创建匿名对象,它将保留您提供的原始对象(参见上面的示例)。只有在生成的组中执行类似于
.Select(p=>new{p.Discrict})
的操作时,才会创建匿名对象。

已经解释了如何使用
GroupBy
。我将讨论第二部分:“转换为
列表
”和“不使用
var

首先,关于将
GroupBy
的结果转换为
List
:您不能这样做。
GroupBy
操作的结果是一个
IEnumerable
(假设您是按
string
属性分组的),它本身就是
IEnumerable
IEnumerable
;每个内部
IEnumerable
对应于找到的每个键,您可以使用
key
属性检查每种情况下的键:

var grouped = persons.GroupBy(p => p.District);
foreach(var group in grouped) 
{
    Console.WriteLine($"People in disctrict {group.Key}:");
    foreach(var person in group)
    {
        Console.WriteLine(person.Name);
    }
}
你可以回去查看未分组人员的完整列表,但我认为这没有多大意义:

var ungrouped = grouped.SelectMany(g => g).ToList<Person>();
var ungroup=group.SelectMany(g=>g.ToList();
关于不使用
var
:您当然可以将变量定义为
IEnumerable
,但我看不出这样做有什么好处

编辑:如果其他答案表明您实际上想做的是对数据进行排序,而不是对其进行分组,则所有这些都不适用


根据您的评论编辑:“我希望在grpByP变量的值中保留ID和名称,因为使用匿名类型将只包括地区和级别”-
GroupBy
不会创建匿名对象,它将保留您提供的原始对象(参见上面的示例)。只有在您执行类似于
的操作时,才会创建匿名对象。在生成的组中选择(p=>new{p.Discrict})

从评论中听起来,您只想按地区,然后按级别对列表进行排序。这很容易

List<Person> result = persons.OrderBy(p => p.District).ThenBy(p => p.Level).ToList();
List result=persons.OrderBy(p=>p.District).ThenBy(p=>p.Level.ToList();

从评论中听起来,你只是想按地区,然后按级别对列表进行排序。这很容易

List<Person> result = persons.OrderBy(p => p.District).ThenBy(p => p.Level).ToList();
List result=persons.OrderBy(p=>p.District).ThenBy(p=>p.Level.ToList();

我想你想要的是这样的东西

List<Person> persons = new List<Person>
{
    new Person()
    {
        ID = "1",
        Name = "Joe",
        District = "Columbia",
        Level = "10"
    },
    new Person()
    {
        ID = "2",
        Name = "Beth",
        District = "Columbia",
        Level = "10"
    },
    new Person()
    {
        ID = "3",
        Name = "Jim",
        District = "Washington",
        Level = "11"
    }
};  //this already has values
var grpByP = persons
    .GroupBy(p => new { p.District, p.Level })
    .Select(g => new
    {
        g.Key,
        People = g.ToList<Person>()
    });

foreach (var g in grpByP)
{
    Console.WriteLine("Group:");
    Console.WriteLine(g.Key.District);
    Console.WriteLine(g.Key.Level);
    Console.WriteLine("People:");
    foreach (Person p in g.People)
        Console.WriteLine(p.Name);
    Console.WriteLine();
}
Console.ReadLine();
List persons=新列表
{
新人()
{
ID=“1”,
Name=“乔”,
District=“Columbia”,
级别=“10”
},
新人()
{
ID=“2”,
Name=“Beth”,
District=“Columbia”,
级别=“10”
},
新人()
{
ID=“3”,
Name=“吉姆”,
地区=“华盛顿”,
Level=“11”
}
};  //这已经有了价值
风险值grpByP=人
.GroupBy(p=>new{p.District,p.Level})
.选择(g=>new
{
g、 钥匙,
People=g.ToList()
});
foreach(grpByP中的var g)
{
控制台写入线(“组:”);
控制台写入线(g.Key.District);
控制台写入线(g键级);
Console.WriteLine(“人:”);
foreach(p人与g人)
Console.WriteLine(p.Name);
Console.WriteLine();
}
Console.ReadLine();
输出:-

组: 哥伦比亚10 人: 乔 贝丝

组: 华盛顿11 人: 吉姆


我想你在追求这样的东西

List<Person> persons = new List<Person>
{
    new Person()
    {
        ID = "1",
        Name = "Joe",
        District = "Columbia",
        Level = "10"
    },
    new Person()
    {
        ID = "2",
        Name = "Beth",
        District = "Columbia",
        Level = "10"
    },
    new Person()
    {
        ID = "3",
        Name = "Jim",
        District = "Washington",
        Level = "11"
    }
};  //this already has values
var grpByP = persons
    .GroupBy(p => new { p.District, p.Level })
    .Select(g => new
    {
        g.Key,
        People = g.ToList<Person>()
    });

foreach (var g in grpByP)
{
    Console.WriteLine("Group:");
    Console.WriteLine(g.Key.District);
    Console.WriteLine(g.Key.Level);
    Console.WriteLine("People:");
    foreach (Person p in g.People)
        Console.WriteLine(p.Name);
    Console.WriteLine();
}
Console.ReadLine();
List persons=新列表
{
新人()
{
ID=“1”,
Name=“乔”,
District=“Columbia”,
级别=“10”
},
新人()
{
ID=“2”,
Name=“Beth”,
District=“Columbia”,
级别=“10”
},
新人()
{
ID=“3”,
Name=“吉姆”,
地区=“华盛顿”,
Level=“11”
}
};  //这已经有了价值
风险值grpByP=人
.GroupBy(p=>new{