简体   繁体   English

根据另一个列表条件过滤列表

[英]Filter a list based on another list condition

I have two lists, one has data that comes from the client, and the other one comes from my DB, which means that this data is already contained in my DB.我有两个列表,一个包含来自客户端的数据,另一个来自我的数据库,这意味着这些数据已经包含在我的数据库中。

What I am trying to do is, based on my client's list, filter it with my database list and return only the data that do not contain in my DB, so I can handle the non-duplicates one before inserting it.我想要做的是,根据我的客户列表,用我的数据库列表过滤它并只返回不包含在我的数据库中的数据,这样我就可以在插入之前处理非重复的数据。

To filter this data, I am trying to use LINQ with multiple conditions (bank data).为了过滤此数据,我尝试使用具有多个条件(银行数据)的 LINQ。

private List<PrePaymentBalanceQuery> FiltraConsultasNaoProcessadas(List<InfoBancariaLoja> consultasAProcessar, List<PrePaymentBalanceQuery> consultasProcessadas)
{
  List<BalanceQuery> result = new List<BalanceQuery>();

  clientList.ForEach(y =>
  {
    result = dbList.Where(x =>
      (y.BankCode != x.BankCode) ||
      (y.Agency != x.Agency) ||
      (y.AccountNumber != x.AccountNumber)).ToList();
  });

  return result;
}

But for some reason, it is not working properly.但由于某种原因,它不能正常工作。 Any idea?任何的想法?

Thanks谢谢

Let's say you have a class like below:假设您有一个如下所示的类:

class CustomerInformation
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

As you said, you have two lists, let's say you have two lists like below:正如您所说,您有两个列表,假设您有两个列表,如下所示:

List<CustomerInformation> dbList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"}
        };

        List<CustomerInformation> csutomerList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"},
            new CustomerInformation{Id=5, FirstName="Anny", LastName="Bishwas"},
            new CustomerInformation{Id=6, FirstName="Kabita", LastName="Roy"},
            new CustomerInformation{Id=7, FirstName="Zahidul", LastName="Emon"}
        };

Now you want to get those DB list that are not present in the customer list with somespecific condition, so just try this:现在,您希望通过某些特定条件获取客户列表中不存在的那些数据库列表,因此请尝试以下操作:

 var newList = csutomerList.Where(cusItem => !dbList.Any(dbItem => cusItem.Id == dbItem.Id && cusItem.FirstName == dbItem.FirstName && cusItem.LastName == dbItem.LastName));

it will first find out all the data that are present in both lists and then simply deduct them.它将首先找出两个列表中存在的所有数据,然后简单地扣除它们。
Sample Output:示例输出:

在此处输入图片说明

Full code here:完整代码在这里:

    static void Main(string[] args)
    {
        AvailableData();
        Console.ReadKey();
    }

    public static void AvailableData()
    {
        // Create two lists.
        List<CustomerInformation> dbList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"}
        };

        List<CustomerInformation> csutomerList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"},
            new CustomerInformation{Id=5, FirstName="Anny", LastName="Bishwas"},
            new CustomerInformation{Id=6, FirstName="Kabita", LastName="Roy"},
            new CustomerInformation{Id=7, FirstName="Zahidul", LastName="Emon"}
        };


        var newList = csutomerList.Where(cusItem => !dbList.Any(dbItem => cusItem.Id == dbItem.Id && cusItem.FirstName == dbItem.FirstName && cusItem.LastName == dbItem.LastName)); 

       foreach (var cust in newList)
        {
            Console.WriteLine("Customer Id :{0} | Customer Name: {1} | Last Name: {2} ",cust.Id,cust.FirstName,cust.LastName);
        }
        Console.ReadKey();

    }
}

class CustomerInformation
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

A more LINQ approach would be like.更像 LINQ 方法。 It's tested from my side.这是从我这边测试的。

 result =
        (from cl in clientList 
         where !dbList.Any(x => x.AccountNumber == cl.AccountNumber && x.BankCode == cl.BankCode && x.Agency == cl.Agency)
         select cl).ToList();

A more LINQ approach would be like.更多的 LINQ 方法会像。 It's tested from my side.它是从我这边测试的。

     result =
            (from cl in clientList 
             where !dbList.Any(x => x.AccountNumber == cl.AccountNumber && x.BankCode == cl.BankCode && x.Agency == cl.Agency)
             select cl).ToList();

Preliminary初步的

This answer assumes you are using an ORM such as EF or EF Core.此答案假定您使用的是 ORM,例如 EF 或 EF Core。 The code is not tested, it is only here to give you the right direction to solve your problem.代码没有经过测试,只是为了给你正确的方向来解决你的问题。 Some open questions will need to be answered to reach your final solution.需要回答一些悬而未决的问题才能得出最终解决方案。

Also your question seems contradictory sometimes: you are mentioning client lists, while the function you show returns a List<PrePaymentBalanceQuery> .此外,您的问题有时似乎自相矛盾:您提到的是客户列表,而您显示的函数返回一个List<PrePaymentBalanceQuery> I assume here we are speaking about client lists, and that I could leave aside some unclear points.我假设在这里我们谈论的是客户名单,我可以撇开一些不清楚的地方。 Anyway, if I'm off please let me know and I'll either edit this answer or remove it.无论如何,如果我离开,请告诉我,我将编辑此答案或将其删除。

Analysing the existing code and the question分析现有代码和问题

Since the code is not doing what you want, let's first understand what it does.既然代码没有做你想要的,让我们首先了解它是做什么的。

You want to filter your in-memory Client list based on some data stored in your database.您想根据存储在数据库中的某些数据过滤内存中的Client列表。

clientList.ForEach(y =>
{
    result = dbList.Where(x =>
      (y.BankCode != x.BankCode) ||
      (y.Agency != x.Agency) ||
      (y.AccountNumber != x.AccountNumber)).ToList();
});

return result;

This code is not filtering a Client list.此代码不过滤Client列表。

What it does is, for each Client :它的作用是,对于每个Client

  • Calculate something and store that something into a variable called result .计算一些东西并将其存储到一个名为result的变量中。

So on each successive iteration, the content in the variable result is replaced by new content.因此,在每次连续迭代中,变量result的内容都会被新内容替换。

In the end, the variable result just contains the calculation made for the last client, which is not what you are trying to achieve.最后,变量result只包含为最后一个客户端所做的计算,这不是您想要实现的。

Conclusion: you shouldn't use ForEach here.结论:你不应该在这里使用ForEach ForEach is not a filtering operator. ForEach不是过滤运算符。 Linq has a filtering operator: Where , which should be used here. Linq 有一个过滤操作符: Where ,这里应该使用它。

Side note: ForEach is not a Linq method extension.旁注: ForEach不是 Linq 方法扩展。 It is a method of the List class.它是List类的一个方法。 It might seem surprising at first, but it is for a good reason.乍一看似乎令人惊讶,但这是有充分理由的。 ForEach is not pure (in the functional programming sense), it will introduce side effects, so it is against the general principles of Linq. ForEach不是纯粹的(在函数式编程意义上),它会引入副作用,因此违背了 Linq 的一般原则。 Purity is not enforced in Linq, but is generally desirable.在 Linq 中不强制执行纯度,但通常是可取的。

How to try to solve this如何尝试解决这个问题

Here is a first version filtering the clientList :这是过滤clientList的第一个版本:

var FilteredClientList = clientList.Where(c => !dbList
      .Any(dbc =>
          (c.BankCode == dbc.BankCode)
          && (c.Agency == dbc.Agency)
          && (c.AccountNumber == dbc.AccountNumber))
  );

return FilteredClientList;

What does it do?它有什么作用?

It builds a new client list by keeping clients from clientList only if there is no such client in the database.只有在数据库中没有这样的客户端时,它才会通过从clientList保留客户端来构建新的客户端列表。

An in-memory client is considered to be in the database if there exists a database client that has the same Bankcode , the same Agency , and the same AccountNumber .如果存在具有相同Bankcode 、相同Agency和相同AccountNumber的数据库客户端,则认为内存中客户端在数据库中。

However, there is a problem.但是,有一个问题。 While this works functionally, it makes potentially a lot of calls to your database: one for each client.虽然这在功能上有效,但它可能会对您的数据库进行大量调用:每个客户端一个。

To understand this, you have to be aware of the difference between Linq to Objects and Linq to Entities.要理解这一点,您必须了解 Linq to Objects 和 Linq to Entities 之间的区别。

See linq to entities vs linq to objects - are they the same?参见linq to entity vs linq to objects - 它们相同吗?

How to fix this?如何解决这个问题? it depends on your particular situation.这取决于您的具体情况。 If your client list is small, you could keep it that way, and be willing to pay for a SQL query for each of your clients.如果您的客户列表很小,您可以保持这种状态,并愿意为每个客户的 SQL 查询付费。

If your database list is small, you could simply get it in memory first, and do all the work in memory.如果你的数据库列表很小,你可以简单地先把它放在内存中,然后在内存中完成所有工作。

var ClientsFromDb = dbList.
    .Select(c => new 
    {
        c.BankCode,
        c.Agency,
        c.AccountNumber
    })
    .ToList()
    
var FilteredClientList = clientList.Where(c => !ClientsFromDb
      .Any(cc =>
          (c.BankCode == cc.BankCode)
          && (c.Agency == cc.Agency)
          && (c.AccountNumber == cc.AccountNumber))
  );

This might also be improved by the use of a Join operator.这也可以通过使用Join运算符来改进。

But what if your database client list is too big?但是如果您的数据库客户列表太大怎么办?

You could first retrieve all the matching clients in your database, in one database query, and then use that in-memory list to filter your actual list.您可以首先在一个数据库查询中检索数据库中所有匹配的客户端,然后使用该内存列表来过滤您的实际列表。

See Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator for pointers.请参阅本地序列不能在查询运算符的 LINQ to SQL 实现中使用,但用于指针的 Contains() 运算符除外

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM