You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:47:18