LINQ to Object - 如何为子组实现 WHERE 子句“如果至少有一个元素是”

Posted

技术标签:

【中文标题】LINQ to Object - 如何为子组实现 WHERE 子句“如果至少有一个元素是”【英文标题】:LINQ to Object - How to implement WHERE clause `If at least one of the elements is` for sub-group 【发布时间】:2021-12-16 04:57:13 【问题描述】:

我有一种无序记录:

public class Row 
    public string Client  get; set; 
    public string Account  get; set; 
    public string Status  get; set; 

它的实例化是:

List<Row> accounts = new List<Row>() 
    new Row()  Client = "123", Account = "123.def", Status = "Open" ,
    new Row()  Client = "456", Account = "456.def", Status = "Closed" ,
    new Row()  Client = "123", Account = "123.abc", Status = "Open" ,
    new Row()  Client = "789", Account = "789.abc", Status = "Open" ,
    new Row()  Client = "456", Account = "456.abc", Status = "Closed" ,
    new Row()  Client = "789", Account = "789.ghi", Status = "Open" ,
    new Row()  Client = "789", Account = "789.def", Status = "Closed" ,
    new Row()  Client = "789", Account = "789.jkl", Status = "Open" ,
;

输出是:

+--------+---------+--------+
| Client | Account | Status |
+--------+---------+--------+
| 123    | 123.def | Open   |
+--------+---------+--------+
| 456    | 456.def | Closed |
+--------+---------+--------+
| 123    | 123.abc | Open   |
+--------+---------+--------+
| 789    | 789.abc | Open   |
+--------+---------+--------+
| 456    | 456.abc | Closed |
+--------+---------+--------+
| 789    | 789.ghi | Open   |
+--------+---------+--------+
| 789    | 789.def | Closed |
+--------+---------+--------+
| 789    | 789.jkl | Open   |
+--------+---------+--------+

之后,为了进一步操作对象,我输入了以下附加类型:

public class Client 
    public string Code  get; set; 
    public List<Account> Accounts  get; set; 


public class Account 
    public string Number  get; set; 
    public string Status  get; set; 

并对按客户字段分组的行进行选择投影:

List<Client> clients = accounts
    .GroupBy(x => x.Client)
    .Select(y => new Client() 
        Code = y.Key,
        Accounts = y.GroupBy(z => z.Account)
            .Select(z => new Account() 
                Number = z.First().Account,
                Status = z.First().Status
            ).ToList()
    ).ToList();

我得到了输出:

+------+------------------+
| Code | Accounts         |
|      +---------+--------+
|      | Number  | Status |
+------+---------+--------+
| 123  | 123.def | Open   |
|      +---------+--------+
|      | 123.abc | Open   |
+------+---------+--------+
| 456  | 456.def | Closed |
|      +---------+--------+
|      | 456.abc | Closed |
+------+---------+--------+
| 789  | 789.abc | Open   |
|      +---------+--------+
|      | 789.ghi | Open   |
|      +---------+--------+
|      | 789.def | Closed |
|      +---------+--------+
|      | 789.jkl | Open   |
+------+---------+--------+

但是,我的问题是: 如何为过滤的Accounts 子组实现 WHERE 子句?

例如:

• How where-clause for logic: get clients, all of whose accounts is open for getting this?:

+------+------------------+
| Code | Accounts         |
|      +---------+--------+
|      | Number  | Status |
+------+---------+--------+
| 123  | 123.def | Open   |
|      +---------+--------+
|      | 123.abc | Open   |
+------+---------+--------+

• How where-clause for logic: get clients, who have at least one account is open? for getting this?:

+------+------------------+
| Code | Accounts         |
|      +---------+--------+
|      | Number  | Status |
+------+---------+--------+
| 123  | 123.def | Open   |
|      +---------+--------+
|      | 123.abc | Open   |
+------+---------+--------+
| 789  | 789.abc | Open   |
|      +---------+--------+
|      | 789.ghi | Open   |
|      +---------+--------+
|      | 789.def | Closed |
|      +---------+--------+
|      | 789.jkl | Open   |
+------+---------+--------+

dotnetfiddle 上的完整互动 code listing

【问题讨论】:

【参考方案1】:

查询:获取客户,其所有账户均已开通

var ClientsWithAllAccountsAsOpen = clients
   .Where(c => c.Accounts
       .All(a => a.Status == "Open"));
// Add ToList() or equivalent if you need to materialise.

查询:获取至少有一个账户已开通的客户

var ClientsWithAtLeastOneOpenAccounts = clients
   .Where(c => c.Accounts
       .Any(a => a.Status == "Open"));
// Add ToList() or equivalent if you need to materialise.

【讨论】:

【参考方案2】:

get clients, all of whose accounts is open:

var openAccountsByClient = accounts
    .Where(e => e.Status == "Open")
    .GroupBy(x => x.Client)
    .Select(y => new Client() 
       ...
    ).ToList();

get clients, who have at least one account is open?:

var accountsByClientsWithOneAccount = accounts
    .GroupBy(x => x.Client)
    .Where(x => x.Any(e => e.Status == "Open"))
    .Select(y => new Client() 
       ...
    ).ToList();

【讨论】:

以上是关于LINQ to Object - 如何为子组实现 WHERE 子句“如果至少有一个元素是”的主要内容,如果未能解决你的问题,请参考以下文章

LINQ to Object——延时执行的Enumerable类方法

C# Object to Json to Xml,如何为数组项生成xml元素

如何为属性定义别名

为啥 linq to object 手动实现迭代器?

Linq To Sql进阶系列用object的动态查询与保存log篇

Linq To SQL和Linq To Object的批量操作InsertAllOnSubmit介绍