private static void Main()
{
var accounts = new List<Account>()
{
new Account { PrimaryId = 1, SecondaryId = 10 },
new Account { PrimaryId = 1, SecondaryId = 12 }
};
}
public class Account
{
public int PrimaryId { get; set; }
public IList<int> SecondaryIds { get; set; }
public int SecondaryId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
假设我有上面的代码,我想按PrimaryId分组并将SecondaryId合并到SecondaryIds中。
例如:
// PrimaryId = 1
// SecondaryIds = 10, 12
Run Code Online (Sandbox Code Playgroud)
如何才能实现呢?
到目前为止我已经这样做了
var rs = accounts.GroupBy(g => g.PrimaryId == 1)
.Select(s => new Accounts
{ PrimaryId = 1, SecondaryIds = new List<int>() { /*???*/ } });
Run Code Online (Sandbox Code Playgroud)
LINQGroupBy
最简单的形式采用一个 lambda,该 lambda 返回分组依据的 Key。.GroupBy(a => a.PrimaryId)
。它会生成类似“列表的列表”的内容,其中内部列表中的所有内容都具有相同的键。
如果你做了这样的分组,你可以像这样探索它:
var listOfLists = accounts.GroupBy(a => a.PrimaryId);
foreach(var innerList in listOfLists){
Console.WriteLine("Key is: " + innerList.Key);
foreach(Account account in innerList)
Console.WriteLine("Sid is: " + account.SecondaryId);
}
Run Code Online (Sandbox Code Playgroud)
因此,它实际上将您的 Account 对象放入类似于 a 的对象中List<List<Account>>
,除了内部列表有一个Key
属性,该属性告诉您内部列表中的帐户全部共享什么公共值(PrimaryId)
GroupBy 有一种扩展形式,它采用第二个参数“您想要将哪些项目(可能来自原始对象)放入内部列表中?”,我们可以这样使用它:
.GroupBy(a => a.PrimaryId, a => a.SecondaryId)
Run Code Online (Sandbox Code Playgroud)
这将创建类似 a 的东西List<List<int>>
,因为它只是将 secondaryId 拉出并将其放入内部列表中,而不是整个帐户对象。这很好,因为您仍然可以从 获取 PrimaryId,Key
并且帐户中没有其他任何内容
实际上,甚至还有另一种形式的 GroupBy 带有第三个参数,它将获取结果“列表列表”中的每个项目,并允许您对此执行某些操作..
.GroupBy(
a => a.PrimaryId, //derive the key
a => a.SecondaryId, //derive the innerList
(key, innerList) => new Account { PrimaryId = key, SecondaryIds = innerList.ToList() }
)
Run Code Online (Sandbox Code Playgroud)
您可以将第三个参数视为.Select()
您放在 groupby 末尾的参数。它略有不同,并且可能更容易使用,因为“密钥”和“具有该密钥的事物列表”之间有明确的分离
因此,第一个参数(key,
是分组键(PrimaryID
),第二个参数是具有该分组键innerList)
的所有 s 的列表。SecondaryId
我们可以使用这两个信息来创建一个Account
设置了 Primary 和 secondaryIds 的新对象
我在评论中提到,在一个对象中拥有单个 secondaryId 和它们的列表是很奇怪的。我知道你为什么这样做,但如果你想删除 secondaryId 单数并只保留列表,则 groupby会略有改变:
.GroupBy(
a => a.PrimaryId,
a => a.SecondaryId.First(), //take the only item
(key, innerList) => new Account { PrimaryId = key, SecondaryIds = innerList.ToList() }
)
Run Code Online (Sandbox Code Playgroud)
这将能够处理辅助 ID 的单个项目列表,例如如下所示:
var accounts = new List<Account>()
{
new Account { PrimaryId = 1, SecondaryIds = new(){10} },
new Account { PrimaryId = 1, SecondaryIds = new(){12} }
};
Run Code Online (Sandbox Code Playgroud)
var rs = accounts.GroupBy(g => g.PrimaryId == 1)
.Select(s => new Accounts
{ PrimaryId = 1, SecondaryIds = new List<int>() { /*???*/ } });
Run Code Online (Sandbox Code Playgroud)
这样做.GroupBy(g => g.PrimaryId == 1)
将根据 PrimaryId 是否为 1 的评估进行分组。它不会将任何内容过滤为“仅 ID 1”——本质上任何 PrimaryId 1 的内容都会进入一个内部列表,而其他所有内容都会进入另一个内部列表。内部列表Key
的 是一个bool
. 如果您的帐户列表仅包含主 ID 为 1 的帐户对象,那么一切都会好起来的。如果没有的话那就有点乱了
.Select(s => new Accounts
{ PrimaryId = 1, SecondaryIds = new List<int>() { /*???*/ } });
Run Code Online (Sandbox Code Playgroud)
您的带有一个参数的 GroupBy() 生成了类似 a 的内容List<List<Account>>
,因此它意味着s
是内部列表。它实际上IGrouping<Account>
类似于 Account 对象的列表,但具有额外的 Key 属性,可以告诉您分组中所有项目的共同点。
这意味着,因为这.Select
是s
一个s
帐户列表,并且您只需要该列表中每个帐户的secondaryId ,所以您需要另一个Select,这次只s
从其中的每个帐户中提取 secondaryId:
.Select(s => new Accounts
{
PrimaryId = 1,
SecondaryIds = s.Select(acc => acc.SecondaryId)
});
Run Code Online (Sandbox Code Playgroud)
然后你想在该Select上调用 ToList()
.Select(s => new Accounts
{
PrimaryId = 1,
SecondaryIds = s.Select(acc => acc.SecondaryId).ToList()
});
Run Code Online (Sandbox Code Playgroud)
如果我这样做的话我会这样做:
.GroupBy(a => a.PrimaryId)
.Select(g => new Accounts
{
PrimaryId = g.Key,
SecondaryIds = g.Select(acc => acc.SecondaryId).ToList()
});
Run Code Online (Sandbox Code Playgroud)
但是第 3 个参数 GroupBy 更清晰一些..
归档时间: |
|
查看次数: |
2533 次 |
最近记录: |