C# Linq查询:筛选客户未购买的Top250产品(DataTable场景)
解决筛选客户未购买的前250个排序产品问题
看起来你在处理DataTable数据筛选的时候卡壳了,我来帮你捋清楚逻辑并给出可行的代码实现~
你提到手里有几个核心DataTable:按Rank排序的产品表Product、订单表头表OrderHistory、订单明细表OrderLines还有客户历史表,目标是找出某个客户从未购买过的前250个产品。核心逻辑其实很清晰:先拿到该客户已购的所有产品ID,再从排序好的产品表里排除这些ID,最后取前250条就行。
第一步:获取客户已购买的产品ID集合
首先得把客户所有的购买记录关联起来——从订单表头拿到该客户的所有订单,再从订单明细里提取这些订单对应的产品ID;如果客户历史表也有购买记录,别忘了把这部分也加进去,最后去重避免重复ID影响筛选:
// 替换为实际的目标客户ID int targetCustomerId = 123; // 从订单表头筛选该客户的所有订单ID var customerOrderIds = OrderHistory.AsEnumerable() .Where(row => row.Field<int>("CustomerId") == targetCustomerId) .Select(row => row.Field<int>("OrderId")) .ToList(); // 从订单明细提取对应产品ID并去重 var purchasedProductIds = OrderLines.AsEnumerable() .Where(row => customerOrderIds.Contains(row.Field<int>("OrderId"))) .Select(row => row.Field<int>("ProductId")) .Distinct() .ToList(); // 补充客户历史表中的购买记录(如果有) var historyProductIds = CustomerHistory.AsEnumerable() .Where(row => row.Field<int>("CustomerId") == targetCustomerId) .Select(row => row.Field<int>("ProductId")) .Distinct() .ToList(); purchasedProductIds.AddRange(historyProductIds); // 转成HashSet提升后续查找效率(数据量大的时候效果明显) var purchasedProductSet = new HashSet<int>(purchasedProductIds.Distinct());
第二步:筛选未购买的产品并取前250
因为你的Product表已经按Rank排好序了,直接排除已购ID后取前250条即可。这里加了异常处理,避免没有符合条件的产品时程序崩溃:
DataTable unpurchasedTop250 = null; try { unpurchasedTop250 = Product.AsEnumerable() .Where(row => !purchasedProductSet.Contains(row.Field<int>("ProductId"))) .Take(250) .CopyToDataTable(); } catch (InvalidOperationException) { // 如果没有找到未购买的产品,克隆Product表结构创建空表 unpurchasedTop250 = Product.Clone(); } // 后续可以对结果表进行操作,比如输出行数 Console.WriteLine($"共找到{unpurchasedTop250.Rows.Count}个未购买的产品");
完整整合示例
把这些逻辑放到你的Program类里,就是这样:
class Program { static DataTable Product = new DataTable("Product"); static DataTable OrderHistory = new DataTable("OrderHeader"); static DataTable OrderLines = new DataTable("OrderLines"); static DataTable CustomerHistory = new DataTable("CustomerHistory"); static void Main(string[] args) { // 这里假设你已经完成了各个DataTable的初始化和数据填充 int targetCustomerId = 123; // 替换为实际客户ID // 1. 收集客户已购产品ID var customerOrderIds = OrderHistory.AsEnumerable() .Where(row => row.Field<int>("CustomerId") == targetCustomerId) .Select(row => row.Field<int>("OrderId")) .ToList(); var purchasedProductIds = OrderLines.AsEnumerable() .Where(row => customerOrderIds.Contains(row.Field<int>("OrderId"))) .Select(row => row.Field<int>("ProductId")) .Distinct() .ToList(); var historyProductIds = CustomerHistory.AsEnumerable() .Where(row => row.Field<int>("CustomerId") == targetCustomerId) .Select(row => row.Field<int>("ProductId")) .Distinct() .ToList(); purchasedProductIds.AddRange(historyProductIds); var purchasedProductSet = new HashSet<int>(purchasedProductIds.Distinct()); // 2. 筛选未购买的前250个产品 DataTable result = null; try { result = Product.AsEnumerable() .Where(row => !purchasedProductSet.Contains(row.Field<int>("ProductId"))) .Take(250) .CopyToDataTable(); } catch (InvalidOperationException) { result = Product.Clone(); } // 处理结果 Console.WriteLine($"筛选完成,共{result.Rows.Count}条未购买产品"); } }
小提示
- 如果你的
Product表不是预先排序好的,记得在筛选前加上.OrderBy(row => row.Field<int>("Rank"))保证排序正确; - 用
HashSet替代List做ID查找,在数据量大的时候能显著提升效率,因为HashSet的查找时间复杂度是O(1),而List是O(n)。
内容的提问来源于stack exchange,提问作者Lee Morgan
相关产品推荐
相关产品推荐

