简体   繁体   中英

How can I increase the speed of filtering a list

I display data in a data grid and want to filter the data with range sliders (slider with two handles). The change-event of the range slider only sets the string variable filterTrigger . The filter itself is triggered via mouseup event.

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 = "";
    }
}

The code is working fluently when I comment out all the lines that start with a discard _ . But of course, I need these lines. The problem is, that they need much processor power. It is still working but when I move the mouse with clicked handle of a filter, the handle is extremely lagging (and my laptop sounds like a helicopter).

I know that a part of the last filter is redundant, because when filterTrigger is foo, foo was already filtered. But filtering only what was not filtered before, will not alone solve the problem, because above I only show two filters but there are actually about ten filters.

So, is there a way I could optimize this code?

When optimizing code the first rule is to measure, preferably with a profiler that can tell you exactly what part of the code takes most of the time.

Second rule would be to use a optimal algorithm, but unless you have a huge number of items and some reasonable way to sort or index said items, linear time is the best you can do.

Here are some guesses and suggestions of things that might be improved:

  • Avoid using .ElementAt , this might create a new enumerator object, and that will take some time. Especially inside inner loops. Prefer to use indexers and/or store it in local variables instead.
  • Avoid using Linq. Linq is great for readability, but it will have some overhead. So when optimizing it might be worthwhile to use regular loops to see if the overhead is significant or not.
  • Try to do all processing in one go. Instead iterating over all items once to find the minimum and once to do the maximum, do both at the same time. Memory is slow, and by doing as much processing of an item as possible when it is already cached helps reduce memory traffic.
  • I would consider replacing RemoveAll with a loop that copies items that pass the check to a empty list. This should help ensure items are copied at most once.

A rule of thumb when optimizing is to use low level language features. These are often easier for the jitter to optimize well. But it may make the code harder to read, so use a profiler to optimize the places that need it the most.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM