按多个条件分组列表,LINQ
Group list by multiple conditions, LINQ
我有 Book
class:
public class Book
{
public int Id {get; set;}
public string Name {get; set;}
public deciaml Price {get; set;}
}
和 books
列表:
List<Book> books = new List<Book>
{
new Book
{
Id = 1,
Name = "AA",
Price = 19.0000M
},
new Book
{
Id = 2,
Name= "BB",
Price = 18.0000M
},
new Book
{
Id = 3,
Name = "CC",
Price = 30.0000M
},
new Book
{
Id = 4,
Name = "DD",
Price = 9.0000M,
},
};
现在我想按价格对列表进行分组,例如便宜、中等、昂贵:
例如,便宜 = 10,中等 = 20,昂贵 = 30
分组列表如下:
List<(decimal category, List<Book> books)
{
category: 10
books: List<Book>() {Book {4, "DD", 9.0000M}},
category: 20
books: List<Book>() {Book {1, "AA", 19.0000M}, Book {2, "BB", 18.0000M}},
category: 30
books: List<Book>() {Book {3, "CC", 30.0000M}},
}
更新
books.GroupBy(book => book.Price).Select(group => (group.Key, group.ToList()));
我可以得到分组的图书列表,但是不能按多个条件分组。
更新
感谢大家的快速回答,看来 DotNet Developer
的回答简短而贴心。
books.GroupBy(book => book.Price <= cheap ? cheap :
(book.Price > cheap && book.Price <= middle ? middle : expensive))
.Select(group => (group.Key, group.ToList()))
GroupBy
运算符需要 return 作为组键的函数或表达式。您可以根据价格使用此 return 组“名称”:
var bins=books.GroupBy(b=> b.Price switch {
<=10 =>"cheap",
>10 and <= 20 => " medium",
_ => "expensive"})
.ToDictionary(g=>g.Key,g=>g);
结果是包含每个类别及其内容的字典:
Console.WriteLine(JsonSerializer.Serialize(bins));
-------
{
" medium":[{"Id":1,"Name":"AA","Price":19.0000},{"Id":2,"Name":"BB","Price":18.0000}],
"expensive":[{"Id":3,"Name":"CC","Price":30.0000}],
"cheap":[{"Id":4,"Name":"DD","Price":9.0000}]
}
我在 GroupBy
中使用了模式匹配来适应单个 lambda 中的所有条件。不过,这可能是一个单独的功能:
string BookToBins(Book b)
{
if (b.Price <= 10) return "cheap";
if (b.Price <= 20) return "medium";
return "expensive";
}
...
var bins=books.GroupBy(BookToBins)
.ToDictionary(g=>g.Key,g=>g);
首先 - 将类别添加到列表
var newBookList = BookList.Select(x=> new { Book = x,
Category = x.Price <= 10 ? 10 :
x.Price <= 20 ? 20 :
30 } ).ToList();
然后按此类别分组:
var GroupedBooks = newBookList.GroupBy(x=>x.Category);
foreach(var category in GroupedBooks.Keys) {
Console.WriteLine("category : {0}", category);
foreach(var b in GroupedBooks[Keys].Select(x=>x.Book))
Console.Write("Book {0}, \"{1}\", {2}",b.Id, b.Name, b.Price);
}
类似的东西?
使用三元条件运算符
books.GroupBy(b => b.Price < 10 ? 10 : (b.Price < 20 ? 20 : 30));
如果您不一定受特定类别值的约束,而是希望按可被 10
整除的价格对图书进行分组(即 10
、20
、30
、40
等),您可以通过将 Price
四舍五入到最接近的 10
并将其用作您的 group-by-value.
这是一个例子,使用 Math.Ceiling()
进行舍入:
Math.Ceiling(value / 10) * 10 // Round 'value' upwards to nearest 10
应用为 group-by-condition:
List<(decimal Category, List<Book> Books)> groupedBooks = books
.GroupBy(book => Math.Ceiling(book.Price / 10) * 10,
(category, booksInCategory) => (
Category: category,
Books: booksInCategory.ToList() ))
.OrderBy(gr => gr.Category)
.ToList();
使用您为 books
提供的示例列表,生成的 groupedBooks
包含:
Category: 10
Book: { Id: 4 Name: DD Price: 9.0000 }
Category: 20
Book: { Id: 1 Name: AA Price: 19.0000 }
Book: { Id: 2 Name: BB Price: 18.0000 }
Category: 30
Book: { Id: 3 Name: CC Price: 30.0000 }
示例 fiddle here.
我有 Book
class:
public class Book
{
public int Id {get; set;}
public string Name {get; set;}
public deciaml Price {get; set;}
}
和 books
列表:
List<Book> books = new List<Book>
{
new Book
{
Id = 1,
Name = "AA",
Price = 19.0000M
},
new Book
{
Id = 2,
Name= "BB",
Price = 18.0000M
},
new Book
{
Id = 3,
Name = "CC",
Price = 30.0000M
},
new Book
{
Id = 4,
Name = "DD",
Price = 9.0000M,
},
};
现在我想按价格对列表进行分组,例如便宜、中等、昂贵:
例如,便宜 = 10,中等 = 20,昂贵 = 30 分组列表如下:
List<(decimal category, List<Book> books)
{
category: 10
books: List<Book>() {Book {4, "DD", 9.0000M}},
category: 20
books: List<Book>() {Book {1, "AA", 19.0000M}, Book {2, "BB", 18.0000M}},
category: 30
books: List<Book>() {Book {3, "CC", 30.0000M}},
}
更新
books.GroupBy(book => book.Price).Select(group => (group.Key, group.ToList()));
我可以得到分组的图书列表,但是不能按多个条件分组。
更新
感谢大家的快速回答,看来 DotNet Developer
的回答简短而贴心。
books.GroupBy(book => book.Price <= cheap ? cheap :
(book.Price > cheap && book.Price <= middle ? middle : expensive))
.Select(group => (group.Key, group.ToList()))
GroupBy
运算符需要 return 作为组键的函数或表达式。您可以根据价格使用此 return 组“名称”:
var bins=books.GroupBy(b=> b.Price switch {
<=10 =>"cheap",
>10 and <= 20 => " medium",
_ => "expensive"})
.ToDictionary(g=>g.Key,g=>g);
结果是包含每个类别及其内容的字典:
Console.WriteLine(JsonSerializer.Serialize(bins));
-------
{
" medium":[{"Id":1,"Name":"AA","Price":19.0000},{"Id":2,"Name":"BB","Price":18.0000}],
"expensive":[{"Id":3,"Name":"CC","Price":30.0000}],
"cheap":[{"Id":4,"Name":"DD","Price":9.0000}]
}
我在 GroupBy
中使用了模式匹配来适应单个 lambda 中的所有条件。不过,这可能是一个单独的功能:
string BookToBins(Book b)
{
if (b.Price <= 10) return "cheap";
if (b.Price <= 20) return "medium";
return "expensive";
}
...
var bins=books.GroupBy(BookToBins)
.ToDictionary(g=>g.Key,g=>g);
首先 - 将类别添加到列表
var newBookList = BookList.Select(x=> new { Book = x,
Category = x.Price <= 10 ? 10 :
x.Price <= 20 ? 20 :
30 } ).ToList();
然后按此类别分组:
var GroupedBooks = newBookList.GroupBy(x=>x.Category);
foreach(var category in GroupedBooks.Keys) {
Console.WriteLine("category : {0}", category);
foreach(var b in GroupedBooks[Keys].Select(x=>x.Book))
Console.Write("Book {0}, \"{1}\", {2}",b.Id, b.Name, b.Price);
}
类似的东西?
使用三元条件运算符
books.GroupBy(b => b.Price < 10 ? 10 : (b.Price < 20 ? 20 : 30));
如果您不一定受特定类别值的约束,而是希望按可被 10
整除的价格对图书进行分组(即 10
、20
、30
、40
等),您可以通过将 Price
四舍五入到最接近的 10
并将其用作您的 group-by-value.
这是一个例子,使用 Math.Ceiling()
进行舍入:
Math.Ceiling(value / 10) * 10 // Round 'value' upwards to nearest 10
应用为 group-by-condition:
List<(decimal Category, List<Book> Books)> groupedBooks = books
.GroupBy(book => Math.Ceiling(book.Price / 10) * 10,
(category, booksInCategory) => (
Category: category,
Books: booksInCategory.ToList() ))
.OrderBy(gr => gr.Category)
.ToList();
使用您为 books
提供的示例列表,生成的 groupedBooks
包含:
Category: 10
Book: { Id: 4 Name: DD Price: 9.0000 }
Category: 20
Book: { Id: 1 Name: AA Price: 19.0000 }
Book: { Id: 2 Name: BB Price: 18.0000 }
Category: 30
Book: { Id: 3 Name: CC Price: 30.0000 }
示例 fiddle here.