鉴于以下课程:
public class Transaction
{
public string Category { get; set; }
public string Form { get; set; }
}
如何获得按Category
和Form
分组的交易分组?
基本上我希望它输出如下:
Category 1
Form 1
Transaction1
Transaction2
Transaction3
...
Form 2
Transaction1
Transaction2
Transaction3
...
Category 2
Form 1
Transaction1
Transaction2
Transaction3
...
Form 2
Transaction1
Transaction2
Transaction3
...
答案 0 :(得分:7)
这是一个使用嵌套的foreach循环的例子,我不知道如何在单个linq语句中执行此操作,可能有很多selectmanys?
var transactions = new[]{
new{Category = "1", Form = "1", Title = "Trans1" },
new{Category = "1", Form = "1", Title = "Trans2" },
new{Category = "1", Form = "1", Title = "Trans3" },
new{Category = "1", Form = "2", Title = "Trans1" },
new{Category = "1", Form = "2", Title = "Trans2" },
new{Category = "1", Form = "2", Title = "Trans3" },
new{Category = "2", Form = "1", Title = "Trans1" },
new{Category = "2", Form = "1", Title = "Trans2" },
new{Category = "2", Form = "1", Title = "Trans3" },
new{Category = "1", Form = "3", Title = "Trans1" },
new{Category = "1", Form = "3", Title = "Trans2" },
new{Category = "1", Form = "3", Title = "Trans3" },
};
foreach(var byCategory in transactions.GroupBy(x => x.Category))
{
Console.WriteLine(byCategory.Key);
foreach(var byForm in byCategory.GroupBy(x => x.Form))
{
Console.WriteLine("\t" + byForm.Key);
foreach(var trans in byForm)
{
Console.WriteLine("\t\t" + trans.Title);
}
}
}
仅仅因为我好奇我想出了以下内容,你不应该在生产代码中使用它,因为它很荒谬(如果你有这样的数据结构,它应该分解成类似的东西) Dictionary<CategoryName, FormGroup>
或有意义类型的内容)
Dictionary<string, Dictionary<string, List<string>>> tooManyDictionaries = transactions
.GroupBy(x => x.Category)
.ToDictionary(
catGroup => catGroup.Key,
catGroup => catGroup
.GroupBy(x => x.Form)
.ToDictionary(
formGroup => formGroup.Key,
formGroup => formGroup.Select(x => x.Title).ToList()));
答案 1 :(得分:7)
我最终得到了以下内容,因为在对集合进行迭代之前需要完成分组。
播种某些交易
var cats = new[] { "Category 1", "Category 2", "Category 3" };
var frms = new[] { "Form 1", "Form 2", "Form 3" };
var transactions = new List<Transaction>();
for (var i = 0; i <= 150; i++)
{
transactions.Add(new Transaction
{
Category = i % 2 == 0 ? cats[0] : i % 3 == 0 ? cats[1] : cats[2],
Form = i % 5 == 0 ? frms[0] : i % 7 == 0 ? frms[1] : frms[2]
});
}
分组
var groupedTransactions = transactions.GroupBy(x => x.Category)
.Select(x => new
{
Category = x.Key,
Forms = x.ToList()
.GroupBy(y => y.Form)
});
将其写入控制台
foreach (var group in groupedTransactions.OrderBy(x => x.Category))
{
Console.WriteLine(group.Category);
foreach (var form in group.Forms.OrderBy(x => x.Key))
{
Console.WriteLine("\t" + form.Key);
foreach (var transaction in form)
{
Console.WriteLine("\t\t" + transaction.Id);
}
}
}
答案 2 :(得分:1)
基本上,第一组应包含您稍后需要分组的每条信息,然后在重复分组时,删除与该分组级别相关的一条信息。根据需要多次这样做。
ValueTuple
可以提供很多帮助,因为它可以让你拥有一个可以传递给另一种类型的复合键。否则使用匿名类型,您需要依赖类型推断将组传递给其他人。 ValueTuple
的一个问题是,由于某种原因你不能拥有1元组,所以在这种情况下你需要按单个属性分组而不是使用元组。
如果您的数据结构中已存在层次关系,则可能不需要按Tuple
进行分组。
var groups =
transactions
.GroupBy(tran => (
Category: tran.Category,
Form: tran.Form
)).GroupBy(group => group.Key.Form)
.ToList();
类型变得非常复杂,因此使用类型推断和重构工具以避免在可能的情况下找出特定类型。例如,上面的结果只有以下类型:
List<IGrouping<string, IGrouping<(string Category, string Form), Transaction>>>