Скорость выполнения итерации через DrawingCollection по сравнению с использованием Contains()

#c# #.net #wpf #optimization

#c# #.net #wpf #оптимизация

Вопрос:

У меня есть компонент WPF, показывающий коллекцию Equipments . Каждый из них Equipments содержит один или более Coordinate . В MouseMove моем компоненте вызывается функция, проверяющая, находится ли мышь в данный момент в пределах границ любого Coordinate из любых Equipment . Если это так, то Equipment в вопросе возвращается указание на то, что должно быть показано всплывающее окно с текстовой информацией о Equipment .

Помимо этого, все Coordinates содержат ImageDrawing , для каждого из которых Equipment отображается символ (символ, на который пользователь наводит курсор мыши, чтобы увидеть всплывающий текст). Они помещены в отдельный DrawingGroup для ускорения рендеринга. Еще одним преимуществом этого является то, что если некоторые из них Equipments должны быть скрыты, мы можем просто удалить их Coordinates' ImageDrawing из DrawingGroup , и они все равно останутся в списке Equipments (как и должны быть).

Однако это не мешает отображению всплывающего окна при наведении курсора мыши на Coordinate , поскольку оно отделено от DrawingGroup . Итак, чтобы проверить, должно ли отображаться текстовое всплывающее окно, я должен проверить, находится ли мышь в пределах любого Coordinate , а также проверить, есть ли ImageDrawing для этого Coordinate в DrawingGroup .

Переходя к моему вопросу (tl; dr): какой способ перебора всех этих элементов был бы самым быстрым? У меня есть :

 List<Equipment> equipments;
  

И для каждого из них (этот список в 9 случаях из 10 содержит один элемент и никогда не более пяти)

 List<Coordinate> coordinates;
  

Для каждого из них Coordinates я должен проверить, есть ли их ImageDrawing в DrawingCollection (что в данном случае является DrawingGroup.Children ), который, согласно msdn, является ordered collection of Drawing objects.

Чтобы сделать это, я начал с этого:

 foreach (Equipment equipment in equipments)
{
    foreach (Coordinate coordinate in equipment.Coordinates)
    {
        ImageDrawing image = coordinate.ImageDrawing;
        if (image != null)
        {
            if (currentDrawingGroup.Children.Contains(image))
            {
                if (image.Rect.Bottom > y amp;amp; 
                    image.Rect.Top < y amp;amp; 
                    image.Rect.Left < x amp;amp; 
                    image.Rect.Right > x)
                {
                    return equipment;
                }
            }
        }
    }
}
  

Но подумал, что это становится для многих итераций в тех случаях, когда скрыто много оборудования, и что я мог бы изменить это на это (поскольку Children.Contains(image) в любом случае, итерация за кулисами, вероятно, выполняется):

 foreach (var child in currentDrawingGroup.Children)
{
    foreach (Equipment equipment in equipments)
    {
        foreach (Coordinate coordinate in equipment.Coordinates)
        { 
            ImageDrawing image = coordinate.ImageDrawing;
            if (image != null)
            {
                if (image == child)
                {
                    if (image.Rect.Bottom > y amp;amp; 
                        image.Rect.Top < y amp;amp; 
                        image.Rect.Left < x amp;amp; 
                        image.Rect.Right > x)
                    {
                        return equipment;
                    }
                }
            }
        }
    }
}
  

Я знаю, что этот вопрос слишком длинный, и оптимизации, которые я рассматриваю здесь, вероятно, не имеют большого значения в долгосрочной перспективе. Но есть ли способ, которым это можно было бы сделать без такого количества циклов в циклах? Я чувствую, что где-то должно быть LINQ-выражение, помогающее мне, хотя я не знаю, работает ли какое-либо из них быстрее, чем цикл foreach. Способ сортировки объектов ( Equipments скрытие путем удаления их из DrawingGroup и тому подобное) находится вне моего контроля, и его трудно изменить. Заранее большое спасибо.

Комментарии:

1. Вы оценили свои подходы с System.Diagnostics.Stopwatch ? С помощью этого вы можете выяснить, какой подход является самым быстрым.

2. Итак, чего именно вы хотите? Меньше кода или быстрее время выполнения?

3. Я предполагаю, что мой вопрос двоякий: моя главная забота, как всегда, заключается в удобочитаемости, но я не хочу, чтобы это требовало слишком больших затрат на производительность. Я, вероятно, надеялся, что будет более читаемое решение, чем любое, которое я мог бы придумать в любом случае. Я проверю с помощью секундомера, чтобы увидеть, есть ли большая разница!

Ответ №1:

если какое-то оборудование должно быть скрыто, не было бы чище позволить оборудованию самому управлять его видимостью? Таким образом, вы просто спрашиваете оборудование, видно ли оно в первую очередь, и пропускаете его, если нет?

Таким образом, ваше оборудование также всегда присутствует, но видно или нет, и при наведении на него курсора мыши вам не придется проверять, находятся ли координаты в DrawingGroup или нет … это уже обработано за вас.

Что касается итерации vs Contains() , функция contains представляет собой линейный поиск, поэтому она будет такой же, как итерация по списку.

Комментарии:

1. Это хорошее решение, но, к сожалению, в данном случае неприменимо. Поскольку это работает сейчас, это оборудование может отображаться сразу в нескольких разных местах (назовем их картами), и установка оборудования как скрытого на одной карте скрыла бы его на всех других. Решение с DrawingGroups было принято, поскольку каждая карта имеет свою собственную DrawingGroup. Отвратительно, я знаю, но трудно изменить (это большой проект, и это всего лишь крошечная его часть).

2. Я принимаю этот ответ, поскольку он отвечает на мой первоначальный вопрос; любая разница между Contains() и итерацией. Что угодно, но только не читаемость.