过滤大集合

时间:2009-10-01 00:45:43

标签: .net collections filter

我有一组MyClass对象,我需要通过17个文件组合来过滤它。

我实现了一个对象MyClassFilter,其中包含17个可能的字段以及每个字段的条件和方法:

bool PassFilter(MyClass ObjectToEvaluate)
{
  return PassFilterVal(this.Workstream, ObjectToEvaluate.WorkStream)
    && PassFilterVal(this.AssignedTo, ObjectToEvaluate.AssignedTo)
    && PassFilterVal(this.ProcessingGroup, ObjectToEvaluate.ProcessingGroup)
    && PassFilterVal(this.ScheduledStart, ObjectToEvaluate.ScheduledStart)
    && PassFilterVal(this.EntityName, ObjectToEvaluate.EntityName)
    && PassFilterVal(this.TaskIDs, ObjectToEvaluate.TaskID)
    && PassFilterVal(this.ElementIDs, ObjectToEvaluate.EntityID)
    && PassFilterVal(this.MappingIDs, ObjectToEvaluate.MappingID)
    && PassFilterVal(this.EntityStatus, ObjectToEvaluate.EntityStatus)
    && PassFilterVal(this.EntityType, ObjectToEvaluate.EntityType)
    && PassFilterVal(this.NumberOfSteps, ObjectToEvaluate.ListOfSteps.Count)
    && PassFilterVal(this.NumberOfDependancies, ObjectToEvaluate.ListOfParentDependancies.Count)
    && PassFilterVal(this.NumberOfOpenIssues, ObjectToEvaluate.ListOfAllIssues.CountOpen)
    && PassFilterVal(this.NumberOfRequirementsLinked, ObjectToEvaluate.RequierementsLinked)
    ;
}

我的收藏有一个方法

ListOfMyClass FilterList(MyClassFilter Filter){
    ListOfMyClass FilteredList = new ListOfMyClass();
    foreach (MyClass Task in this)
    {
      if (Filter.TaskPassFilter(Task))
        FilteredList.Add(Task);
    }
    return FilteredList;
}

只要集合很小就可以正常工作但是当我有500个对象时它开始变得很慢。我搜索过网络,但是所有的例子都在集合中逐个对象,如果它通过或者没有通过字段提出请求。

有关如何提高绩效的任何建议吗?

由于

3 个答案:

答案 0 :(得分:1)

这不应该很慢,除非你的比较很慢。

扫描500个物体应该非常快(当然你没有提到“慢”是什么,或者你的坚硬,但是甚至还是......)。

你的PassFilterVal会因为方法调用而“更加昂贵”,而不是排队比较,但由于它们对所有这些都是相同的,所以我想我们已经坚持了我们所拥有的。

您可以订购参数,以便最具选择性的参数。

这里的目标是利用AND的短路来尽快转储,从而限制实际比较的数量。

您可以做的另一件事是首先针对“最常见的查询”进行优化。

是否始终使用所有标准?如果没有,您应该将比较限制为实际使用的比较。在这种情况下,平等实际上是昂贵的(17个方法调用和17个“未知”复杂性的比较)。如果你有某种通配符或“不关心”的价值,你可以尝试跳过那些比较的。

另一个想法是按所有17个标准对元素进行排序。然后使用二进制搜索匹配所有17个字段的元素,最后迭代其余元素,直到它们符合您的条件。当然,您需要始终对列表进行正确排序,但一旦排序,它就是二进制插入,这将非常快。如果你阅读的内容比你添加到列表中的要多得多,那么这应该是一个净收益。

答案 1 :(得分:0)

嗯。

我为你提出了一个可爱的伎俩:

也许你可以实现.CompareTo(或等同于任何语言;我假设是.NET),以便“更接近”的匹配在顶部。然后,你只需使用一个对插入进行排序的集合,这一切都会发生在你身上。

通过这种方式,你可以循环遍历所有项目,一旦找到一个不匹配的项目,就停止,因为你知道下面的所有项目都不匹配。

我有兴趣看看这是怎么回事。但也许其他人会有更好的建议(如果由于某种原因这很愚蠢,我准备好看起来像个傻瓜。)

答案 2 :(得分:0)

如果没有更多的背景,实际上不可能提出为什么表现如此缓慢。但我可以提供一些线索。如果事情在大约500个项目中变得缓慢,那么可能存在潜伏在某处的O(N ^ 2)算法(或者更糟)。我猜你的一个或多个属性在每次比较过程中遍历一大堆数据。

使用C#中的属性,很难知道它们是如何实现的,例如像NumberOfDependancies这样天真的东西,每次调用时都可以遍历一个非常大的图形。或者它可能正在生成一个列表来计算依赖关系。如果可能的话,我会计算一次这些值,并将它们存储在类中(如果可能的话)。但是,当我看到使用它的上下文时,我看到另一个问题:

PassFilterVal(this.NumberOfDependancies, ObjectToEvaluate.ListOfParentDependancies.Count

如果“ListOfParentDependancies”是IEnumerable<>然后,每次调用它时,您将遍历所有依赖项的列表,以计算数字。

您的过滤功能在性能方面很好。为了优雅,以及可能适度的性能提升,我将按如下方式实现它

IEnumerable<MyClass> FilterList(MyClass filter) {
    foreach (MyClass task in this)
       if (filter.TaskPassFilter(task))
         yield return task;
}