【问题标题】:Array looping and comparing if >2 differences如果> 2个差异,则数组循环和比较
【发布时间】:2019-08-23 09:35:37
【问题描述】:

我正在尝试检查 c# 中的项目主列表与列表数组之间的区别。

不太确定如何以有效的方式构建此逻辑。

例子:

我的主清单是:var MasterOrderIDs = {1,2,3,4}

然后我有一个客户/订单对象,它存储客户 ID 及其订单 ID

CustomerID|OrderID
    1     |  1
    1     |  2
    1     |  3
    1     |  4
    1     |  5
    2     |  1
    2     |  2
    2     |  3
    2     |  4
    2     |  5
    2     |  6
    3     |  2
    3     |  3
    3     |  4

我想返回一个包含 CustomerID 和 OrderIDs 的数组,其中 MasterOrderIDs 的差异小于 2。

类似: var OrderDifferences = new Dictionary<int, List<int>>();

所以对于客户/订单,我想退货:

{[1, [5]], [3, [1]}

这是因为对于 CustomerID 1,有一个 Order ID 5,小于 2 个差值。与 CustomerID 3 类似,有一个 Order ID 1,它出现在 MasterOrderIDs 中,并且差异小于 2。

如何创建这样的支票?

在现实生活场景中,我将拥有大数据,因此想知道什么是最有效的方法。

【问题讨论】:

  • 只是为了说清楚 - 更改到底是什么意思?
  • 我的意思是差异。所以 MasterOrderIDs = {1,2,3,4} 是我要检查每个客户 ID 及其订单的集合。所以 CustomerID 1 的 OrderID 为 {1,2,3,4,5}。因为 OrderID 为“5”,所以相差 1。
  • 还有一个问题。您要处理的预期记录数是多少?我可以想到一些小的优化,但对于真正的表现,也许其他人需要回答。
  • 客户/订单将有 300000 条记录。
  • 在内存中执行此操作会耗费时间/资源。 TBH 我会尝试考虑一些可以在数据库服务器上执行繁重工作的解决方案,但无论如何我会在几分钟内发布答案,因此如果您决定在服务器端执行此操作,您可以将其用作起点。

标签: c# arraylist hashset


【解决方案1】:

根据我们得到的信息,我可以想到两个相对较小的优化。所以我的免责声明是,基本方法仍然是蛮力,也许有更聪明的方法来提取信息,但我们仍然可以执行一些检查以排除一些不必要的数据。

小优化1

我们正在寻找与订单主列表相比最多多一个或少一个订单的客户。换句话说,根据您的示例

var MasterOrderIDs = {1,2,3,4}

拥有 5 个订单的客户(如 customerOrders = { 7, 8, 9, 10, 11 })仍然可能有效,但拥有 6 个订单的客户 customerOrders = { 7, 8, 9, 10, 11, 12 } 则无效。

底数也一样。拥有 3 个订单的客户也可能有效 customerOrders = { 7, 8, 9 },但少于两个订单的客户 customerOrders = { 7, 8 } 则无效。

因此,基于此,我们可以执行我们的第一个小型优化归档客户,这些客户的订单超过 MasterOrderIDs.Count() + 2 或少于 MasterOrderIDs.Count() - 2

小优化2

即使我们在适当的订单范围内,我们也希望确保我们的 orderId 重叠。我们只能允许 1 个订单出现在其中一个列表中,而不出现在另一个列表中。基本上这并不完全是一种优化,但这是我们可以构建查询的第二个标准。

这是:

首先播种一些数据:

class Order
{
    public int CustomerId { get; set; }
    public int OrderId { get; set; }

    public static List<Order> Seed()
    {
        return new List<Order>
        {
            new Order { CustomerId = 1, OrderId = 1},
            new Order { CustomerId = 1, OrderId = 2},
            new Order { CustomerId = 1, OrderId = 3},
            new Order { CustomerId = 1, OrderId = 4},
            new Order { CustomerId = 1, OrderId = 5},
            new Order { CustomerId = 2, OrderId = 1},
            new Order { CustomerId = 2, OrderId = 2},
            new Order { CustomerId = 2, OrderId = 3},
            new Order { CustomerId = 2, OrderId = 4},
            new Order { CustomerId = 2, OrderId = 5},
            new Order { CustomerId = 2, OrderId = 6},
            new Order { CustomerId = 3, OrderId = 2},
            new Order { CustomerId = 3, OrderId = 3},
            new Order { CustomerId = 3, OrderId = 4}
        };
    }
}

然后设置初始数据:

var masterList = new List<int> { 1, 2, 3, 4 };
var upperBorder = masterList.Count() + 2;
var bottomBorder = masterList.Count() - 2;
var orders = Order.Seed();

最后提取我们需要的记录:

var ordersWithinRange = orders
                .GroupBy(o => o.CustomerId)
                .Where(x => x.Count() < upperBorder && x.Count() > bottomBorder && x.Select(o => o.OrderId).Except(masterList).Concat(masterList.Except(x.Select(o => o.OrderId))).Count() < 2)
                .ToDictionary(d => d.Key, d => d.Select(o => o.OrderId).Except(masterList).Concat(masterList.Except(d.Select(o => o.OrderId))).ToList());

再次。这将花费大量计算时间,但我认为它比一系列 for 循环一次过滤一件事要快一些。

【讨论】:

  • 我很难理解这一点:x.Select(o =&gt; o.CensusId).Except(masterList).Concat(masterList.Except(x.Select(o =&gt; o.CensusId))).Count()
  • @IntermediaryDeveloper 这个想法是我们不知道哪个List&lt;int&gt; 包含唯一ID。当我们说Select(o =&gt; o.CensusId).Except(masterList) 时,我们会返回那些从Select 投影但现在在masterList 内的ID。但是,masterList 可能具有唯一 ID。因此,我们对两个列表执行相同的Except 操作,从每个列表中获取唯一值,然后将Concat 它们合并到一个List&lt;int&gt; 中。您可以谷歌C# find unique values for two lists了解更多详细信息。
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 2020-02-15
  • 2015-08-21
  • 2017-10-07
  • 1970-01-01
  • 2017-07-01
  • 2018-11-08
相关资源
最近更新 更多