【问题标题】:Filter a list based on another list condition根据另一个列表条件过滤列表
【发布时间】:2021-11-08 04:02:20
【问题描述】:

我有两个列表,一个有来自客户端的数据,另一个来自我的数据库,这意味着这个数据已经包含在我的数据库中。

我想做的是,根据我的客户列表,用我的数据库列表过滤它,只返回我的数据库中不包含的数据,这样我就可以在插入之前处理不重复的数据。

为了过滤这些数据,我尝试将 LINQ 与多个条件(银行数据)一起使用。

  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();
  });

但由于某种原因,它无法正常工作。有什么想法吗?

谢谢

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    假设你有一个像下面这样的类:

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

    如您所说,您有两个列表,假设您有两个列表,如下所示:

    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));
    

    它将首先找出两个列表中存在的所有数据,然后简单地扣除它们。
    样本输出:

    完整代码在这里:

        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; }
    }
    

    【讨论】:

      【解决方案2】:

      初步

      此答案假定您使用的是 ORM,例如 EF 或 EF Core。代码未经测试,只是在这里为您提供解决问题的正确方向。需要回答一些未解决的问题才能得出最终解决方案。

      您的问题有时似乎是矛盾的:您提到了客户列表,而您显示的函数返回List&lt;PrePaymentBalanceQuery&gt;。我假设我们在这里谈论的是客户名单,我可以撇开一些不清楚的地方。无论如何,如果我离开,请告诉我,我将编辑此答案或将其删除。

      分析现有代码和问题

      既然代码没有做你想做的事,我们先来了解一下它做了什么。

      您想根据存储在数据库中的一些数据过滤内存中的Client 列表。

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

      此代码未过滤 Client 列表。

      它的作用是,对于每个Client

      • 计算一些东西并将其存储到一个名为result的变量中。

      因此在每次连续迭代中,变量result 中的内容都会被新内容替换。

      最后,变量result 只包含为最后一个客户端所做的计算,这不是您想要实现的。

      结论:你不应该在这里使用ForEachForEach 不是过滤运算符。 Linq 有一个过滤操作符:Where,这里应该用到。

      旁注:ForEach 不是 Linq 方法扩展。它是List 类的方法。 起初这似乎令人惊讶,但这是有充分理由的。 ForEach 不是纯粹的(在函数式编程意义上),它会引入副作用,所以它违反了 Linq 的一般原则。 Linq 中不强制执行纯度,但通常是可取的。

      如何尝试解决这个问题

      这是过滤clientList的第一个版本:

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

      它有什么作用?

      只有当数据库中没有这样的客户时,它才会通过让客户远离clientList 来构建一个新的客户列表。

      如果存在具有相同Bankcode、相同Agency 和相同AccountNumber 的数据库客户端,则认为内存中客户端位于数据库中。

      但是,有一个问题。虽然这在功能上有效,但它可能会对您的数据库进行大量调用:每个客户端调用一次。

      要理解这一点,您必须了解 Linq to Objects 和 Linq to Entities 之间的区别。

      linq to entities vs linq to objects - are they the same?

      如何解决这个问题?这取决于您的具体情况。 如果您的客户列表很小,您可以保持这种状态,并愿意为您的每个客户支付 SQL 查询费用。

      如果您的数据库列表很小,您可以先将其放入内存中,然后在内存中完成所有工作。

      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))
        );
      

      这也可以通过使用Join 运算符来改进。

      但是如果您的数据库客户端列表太大怎么办?

      您可以先在一个数据库查询中检索数据库中所有匹配的客户端,然后使用该内存列表过滤您的实际列表。

      有关指针,请参阅Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator

      【讨论】:

        【解决方案3】:

        更像是一种 LINQ 方法。我这边已经测试过了。

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

        【讨论】:

          猜你喜欢
          • 2022-12-22
          • 1970-01-01
          • 1970-01-01
          • 2020-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多