如何在数据表中查找匹配的记录

时间:2013-10-31 16:00:14

标签: c# datatable sum

我有一个包含两个列的数据表:数字和日期,对于示例:

  

125 | 2013年10月20日
  100 | 2013年10月21日
  150 | 2013年10月24日
  225 | 2013年10月24日
  250 | 2013年10月28日
  310 |二○一三年十月三十○日

现在,我想搜索按日期排序的所有记录,其中数字的总和匹配500.我可以很容易地看到第一,第三和第四条记录(125 + 150 + 225 = 500)提供了匹配,但是对于这样的程序,我只能想到在数据表中经过数万次,直到找到正确的匹配。

有人有更明智的想法吗?

1 个答案:

答案 0 :(得分:2)

在最糟糕的情况下,您必须浏览数据集的所有2^n子集,但如果您的所有项目都是非负数,则可以通过item.Number <= 500上的过滤开始。

这是一种可能的Subsets方法(实际上是How to get all subsets of an array?的答案,但不要告诉他们):

public static IEnumerable<IEnumerable<T>> Subsets(this IEnumerable<T> source)
{
    var first = source.FirstOrDefault();
    if (first == null) return new[] { Enumerable.Empty<T>() };

    var others = source.Skip(1).Subsets();
    return others.Concat(others.Select(s => s.Concat(new { first })));
}

获得Subsets方法之后,您可以按如下方式过滤结果,但性能仍然是数十亿(或2^n,如果您想挑剔)。

var sets = items.Where(i => i.Number <= 500)
    .Subsets().Where(s => s.Sum(i => i.Number) == 500);

但是,如果您对Number有约束,那么它是非负的,您可以将Subsets操作与搜索目标总和相结合。这意味着你要定义

public static IEnumerable<IEnumerable<T>> SubsetsAddingUpTo(this IEnumerable<T> source, int target)
{
    // This stopping condition ensures that you will not have to walk the rest of the tree when you have already hit or exceeded your target.
    // It assumes that the Number values are all non-negative.
    if (target < 0) return Enumerable.Empty<IEnumerable<T>>();

    var first = source.FirstOrDefault();
    if (first == null) return Enumerable.Empty<IEnumerable<T>>();

    var tail = source.Skip(1).Where(i => i.Number <= target).ToList();

    var othersIncludingFirst = tail.SubsetsAddingUpTo(target - first.Number);
    var othersExcludingFirst = tail.SubsetsAddingUpTo(target);

    return othersExcludingFirst.Concat(othersIncludingFirst.Select(s => s.Concat(new { first })));
}

因为<= target的检查发生在方法内部,所以您不必进行任何预过滤。但是,您可以在执行搜索之前执行排序,以按层次结构日期顺序为您提供集合。电话会是

var sets = items.OrderByDescending(i => i.Date).SubsetsAddingUpTo(500);

这实际上应该给你体面的表现。最坏的情况(每个项目的数字为0或1)都不会很好(订单2^n),但如果Number的大多数值与您的数量级相似目标总和,就像您的示例中的情况一样,然后停止条件将进入您的救援并为您节省大量不必要的操作。