如何提高过滤列表的速度
How can I increase the speed of filtering a list
我在数据网格中显示数据并希望使用范围滑块(带有两个手柄的滑块)过滤数据。范围滑块的更改事件仅设置字符串变量 filterTrigger
。过滤器本身通过 mouseup 事件触发。
private void ApplyFilter()
{
if (filterTrigger != "")
{
filteredData.Clear();
suitableData.ForEach((item) =>
{
filteredData.Add(item); // create not referenced copy of list suitableData that was created in time consuming calculations
});
switch (filterTrigger)
{
case "foo":
// remove too small and too large Foos
_ = filteredData.RemoveAll(x => x.Foo > fooRangeSliderHandlesMinMax.ElementAt(1) || x.Foo < fooRangeSliderHandlesMinMax.ElementAt(0));
// set new minimum and maximum of range of range slider
barRangeSliderMinimum = filteredData.Min(x => x.Bar) - 0.1;
barRangeSliderMaximum = filteredData.Max(x => x.Bar) + 0.1;
// set new position of range slider handles
barRangeSliderHandlesMinMax = new double[2] { Math.Max(barRangeSliderHandlesMinMax.ElementAt(0), barRangeSliderMinimum + 0.1), Math.Min(barRangeSliderHandlesMinMax.ElementAt(1), barRangeSliderMaximum - 0.1) };
break;
case "bar":
_ = filteredData.RemoveAll(x => x.Bar > barRangeSliderHandlesMinMax.ElementAt(1) || x.Bar < barRangeSliderHandlesMinMax.ElementAt(0));
fooRangeSliderMinimum = filteredData.Min(x => x.Foo) - 0.1;
fooRangeSliderMaximum = filteredData.Max(x => x.Foo) + 0.1;
fooRangeSliderHandlesMinMax = new double[2] { Math.Max(fooRangeSliderHandlesMinMax.ElementAt(0), fooRangeSliderMinimum + 0.1), Math.Min(fooRangeSliderHandlesMinMax.ElementAt(1), fooRangeSliderMaximum - 0.1) };
break;
default:
break;
}
// remove values of foo if filterTrigger was "bar" and vice versa
_ = filteredData.RemoveAll(x => x.Foo > fooRangeSliderHandlesMinMax.ElementAt(1) || x.Foo < fooRangeSliderHandlesMinMax.ElementAt(0) || x.Bar > barRangeSliderHandlesMinMax.ElementAt(1) || x.Bar < barRangeSliderHandlesMinMax.ElementAt(0));
// update data grid data
IFilteredData = filteredData;
dataGrid.Reload();
filterTrigger = "";
}
}
当我注释掉所有以丢弃 _
开头的行时,代码运行流畅。但当然,我需要这些台词。问题是,他们需要很大的处理器能力。它仍在工作,但是当我用单击过滤器的手柄移动鼠标时,手柄非常滞后(我的笔记本电脑听起来像直升机)。
我知道最后一个过滤器的一部分是多余的,因为当filterTrigger为foo时,foo已经被过滤了。但是只过滤之前没有过滤的东西,并不能单独解决问题,因为上面我只显示了两个过滤器,但实际上有大约十个过滤器。
那么,有什么方法可以优化这段代码吗?
在优化代码时,第一个规则是测量,最好使用一个分析器,它可以准确地告诉您代码的哪一部分占用了大部分时间。
第二条规则是使用最佳算法,但除非你有大量的项目和一些合理的方法来排序或索引所述项目,线性时间是你能做的最好的。
以下是一些可能改进的猜测和建议:
- 避免使用
.ElementAt
,这可能会创建一个新的枚举器对象,这将需要一些时间。特别是内部循环。更喜欢使用索引器 and/or 将其存储在局部变量中。
- 避免使用 Linq。 Linq 非常适合可读性,但它会产生一些开销。因此,在优化时,可能值得使用常规循环来查看开销是否显着。
- 尝试一次完成所有处理。而是遍历所有项目一次以找到最小值,一次以求最大值,同时进行这两项操作。内存很慢,在项目已经缓存时尽可能多地处理它有助于减少内存流量。
- 我会考虑将
RemoveAll
替换为一个循环,该循环将通过检查的项目复制到一个空列表中。这应该有助于确保项目最多被复制一次。
优化时的一个经验法则是使用低级语言功能。这些通常更容易让抖动优化好。但它可能会使代码更难阅读,所以使用分析器来优化最需要它的地方。
我在数据网格中显示数据并希望使用范围滑块(带有两个手柄的滑块)过滤数据。范围滑块的更改事件仅设置字符串变量 filterTrigger
。过滤器本身通过 mouseup 事件触发。
private void ApplyFilter()
{
if (filterTrigger != "")
{
filteredData.Clear();
suitableData.ForEach((item) =>
{
filteredData.Add(item); // create not referenced copy of list suitableData that was created in time consuming calculations
});
switch (filterTrigger)
{
case "foo":
// remove too small and too large Foos
_ = filteredData.RemoveAll(x => x.Foo > fooRangeSliderHandlesMinMax.ElementAt(1) || x.Foo < fooRangeSliderHandlesMinMax.ElementAt(0));
// set new minimum and maximum of range of range slider
barRangeSliderMinimum = filteredData.Min(x => x.Bar) - 0.1;
barRangeSliderMaximum = filteredData.Max(x => x.Bar) + 0.1;
// set new position of range slider handles
barRangeSliderHandlesMinMax = new double[2] { Math.Max(barRangeSliderHandlesMinMax.ElementAt(0), barRangeSliderMinimum + 0.1), Math.Min(barRangeSliderHandlesMinMax.ElementAt(1), barRangeSliderMaximum - 0.1) };
break;
case "bar":
_ = filteredData.RemoveAll(x => x.Bar > barRangeSliderHandlesMinMax.ElementAt(1) || x.Bar < barRangeSliderHandlesMinMax.ElementAt(0));
fooRangeSliderMinimum = filteredData.Min(x => x.Foo) - 0.1;
fooRangeSliderMaximum = filteredData.Max(x => x.Foo) + 0.1;
fooRangeSliderHandlesMinMax = new double[2] { Math.Max(fooRangeSliderHandlesMinMax.ElementAt(0), fooRangeSliderMinimum + 0.1), Math.Min(fooRangeSliderHandlesMinMax.ElementAt(1), fooRangeSliderMaximum - 0.1) };
break;
default:
break;
}
// remove values of foo if filterTrigger was "bar" and vice versa
_ = filteredData.RemoveAll(x => x.Foo > fooRangeSliderHandlesMinMax.ElementAt(1) || x.Foo < fooRangeSliderHandlesMinMax.ElementAt(0) || x.Bar > barRangeSliderHandlesMinMax.ElementAt(1) || x.Bar < barRangeSliderHandlesMinMax.ElementAt(0));
// update data grid data
IFilteredData = filteredData;
dataGrid.Reload();
filterTrigger = "";
}
}
当我注释掉所有以丢弃 _
开头的行时,代码运行流畅。但当然,我需要这些台词。问题是,他们需要很大的处理器能力。它仍在工作,但是当我用单击过滤器的手柄移动鼠标时,手柄非常滞后(我的笔记本电脑听起来像直升机)。
我知道最后一个过滤器的一部分是多余的,因为当filterTrigger为foo时,foo已经被过滤了。但是只过滤之前没有过滤的东西,并不能单独解决问题,因为上面我只显示了两个过滤器,但实际上有大约十个过滤器。
那么,有什么方法可以优化这段代码吗?
在优化代码时,第一个规则是测量,最好使用一个分析器,它可以准确地告诉您代码的哪一部分占用了大部分时间。
第二条规则是使用最佳算法,但除非你有大量的项目和一些合理的方法来排序或索引所述项目,线性时间是你能做的最好的。
以下是一些可能改进的猜测和建议:
- 避免使用
.ElementAt
,这可能会创建一个新的枚举器对象,这将需要一些时间。特别是内部循环。更喜欢使用索引器 and/or 将其存储在局部变量中。 - 避免使用 Linq。 Linq 非常适合可读性,但它会产生一些开销。因此,在优化时,可能值得使用常规循环来查看开销是否显着。
- 尝试一次完成所有处理。而是遍历所有项目一次以找到最小值,一次以求最大值,同时进行这两项操作。内存很慢,在项目已经缓存时尽可能多地处理它有助于减少内存流量。
- 我会考虑将
RemoveAll
替换为一个循环,该循环将通过检查的项目复制到一个空列表中。这应该有助于确保项目最多被复制一次。
优化时的一个经验法则是使用低级语言功能。这些通常更容易让抖动优化好。但它可能会使代码更难阅读,所以使用分析器来优化最需要它的地方。