【问题标题】:Speed of iterating through DrawingCollection versus using Contains()通过 DrawingCollection 与使用 Contains() 的迭代速度
【发布时间】:2011-11-11 17:40:29
【问题描述】:

我有一个显示Equipments 集合的 WPF 组件。这些Equipments 中的每一个都包含一个或多个Coordinate。在我的组件上的MouseMove 上,调用一个函数来检查鼠标当前是否悬停在任何Equipment 的任何Coordinate 的范围内。如果是这样,则返回有问题的Equipment,指示应显示一个包含有关Equipment 的文本信息的弹出窗口。

除此之外,所有Coordinates 都包含一个ImageDrawing,它为每个Equipment 显示一个符号(用户将鼠标悬停在该符号上以查看文本弹出窗口)。这些被放在一个单独的DrawingGroup 中以加快渲染速度。这样做的另一个好处是,如果要隐藏某些Equipments,我们可以从DrawingGroup 中删除它们的Coordinates' ImageDrawing,它们仍将保留在Equipments 列表中(应该如此)。

但是,当鼠标悬停在 Coordinate 上时,这并不妨碍弹出窗口的显示,因为它与 DrawingGroup 是分开的。因此,要检查是否要显示文本弹出窗口,我必须检查鼠标是否在任何 Coordinate 的范围内,还要检查 ImageDrawingCoordinate 是否在 @ 987654342@.

关于我的问题(tl;dr):迭代所有这些项目的哪种方式最快?我有:

List<Equipment> equipments;

并且对于其中的每一个(此列表中有 10 次中有 9 次包含一项,并且永远不会超过 5 项)

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 && 
                    image.Rect.Top < y && 
                    image.Rect.Left < x && 
                    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 && 
                        image.Rect.Top < y && 
                        image.Rect.Left < x && 
                        image.Rect.Right > x)
                    {
                        return equipment;
                    }
                }
            }
        }
    }
}

我知道这个问题太长了,从长远来看,我在这里看到的优化可能并不重要。但是有没有办法在没有这么多循环的情况下做到这一点?我觉得应该有一个 LINQ 表达式在某个地方帮助我,尽管我不知道其中任何一个是否比 foreach 循环更快。事物的排序方式(Equipments 被从 DrawingGroup 中删除等隐藏起来)超出了我的控制范围,而且很难改变。提前非常感谢。

【问题讨论】:

  • 您是否使用System.Diagnostics.Stopwatch 评估过您的方法?这样您就可以知道哪种方法最快。
  • 那么你到底想要什么?更少的代码或更快的运行时间?
  • 我想我的问题有两个方面:我主要关心的是可读性,但我不希望它的性能成本太大。我可能希望有一个比我想出的任何解决方案都更具可读性的解决方案。我会用秒表看看有什么不同!

标签: c# .net wpf optimization


【解决方案1】:

如果要隐藏一些设备,让设备自己管理它的可见性不是更干净吗?这样一来,您只需询问设备是否首先可见,如果不可见,则跳过它?

因此您的设备也始终存在,但可见与否,当您将鼠标悬停在其上时,您不必检查坐标是否在绘图组中......它已经为您处理了。

关于迭代与Contains(),包含函数是线性搜索,因此它与遍历列表相同。

【讨论】:

  • 这是一个很好的解决方案,但不幸的是不适用于这种情况。按照现在的工作方式,这些设备可以同时显示在多个不同的地方(我们称之为地图),并且将设备设置为隐藏在一个地图中会隐藏它在所有其他地图中。使用 DrawingGroups 的解决方案已经制定,因为每张地图都有自己的 DrawingGroup。 Icky,我知道,但很难改变(这是一个大项目,这只是其中的一小部分)。
  • 我会接受这个答案,因为它回答了我原来的问题; Contains() 和迭代之间的任何区别。除此以外的任何内容都是可读性。
猜你喜欢
  • 2011-02-06
  • 2011-02-01
  • 2016-12-05
  • 2014-10-07
  • 1970-01-01
  • 2020-07-12
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
相关资源
最近更新 更多