C# Lambda 表达式速度

发布于 2024-08-24 07:57:49 字数 548 浏览 5 评论 0原文

我以前没有使用过很多 lambda 表达式,但我遇到过一种情况,我认为我可以巧妙地使用一个表达式。我有一个约 19,000 条记录的自定义列表,我需要查明列表中是否存在记录,因此我决定尝试以下操作,而不是编写一堆循环或使用 linq 来遍历列表:

for (int i = MinX; i <= MaxX; ++i)
{
    tempY = MinY;

    while (tempY <= MaxY)
    {
        bool exists = myList.Exists(item => item.XCoord == i && item.YCoord == tempY);

        ++tempY;
    }
}

唯一的问题是它执行大约需要 9 - 11 秒。我做错了什么吗?这只是我不应该使用这样的表达式的情况吗?

谢谢。

编辑:抱歉。我应该详细说明。我正在使用 for 和 while 循环创建一个记录列表,并检查该记录是否存在于 myList 中。这是我能想到的唯一方法。我会重新评估它,看看我能得到什么。

I have not used many lambda expressions before and I ran into a case where I thought I could make slick use of one. I have a custom list of ~19,000 records and I need to find out if a record exists or not in the list so instead of writing a bunch of loops or using linq to go through the list I decided to try this:

for (int i = MinX; i <= MaxX; ++i)
{
    tempY = MinY;

    while (tempY <= MaxY)
    {
        bool exists = myList.Exists(item => item.XCoord == i && item.YCoord == tempY);

        ++tempY;
    }
}

Only problem is it take ~9 - 11 seconds to execute. Am I doing something wrong is this just a case of where I shouldn't be using an expression like this?

Thanks.

EDIT: Sorry. I should elaborate. I am creating a list of records with the for and while loop and checking if that record exists in myList. That is the only way I could think of going about it. I will reevaluate it and see what I come with up.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

平生欢 2024-08-31 07:57:49

这段代码对我来说毫无意义,所以很难说你是否做错了。是的,你做错了的可能性很大。

与其显示代码,不如尝试这个。假设您有一个方法完全可以实现您想要的功能。该方法的签名是什么?不是正文,只是签名。

例如,假设您想问“这个点列表是否包含特定点?”那么签名将是

bool Contains(List<Point> list, Point p)

假设您想问问题“这个点列表是否包含此矩形内的任何点?”那么签名将是

bool ContainsAny(List<Point> list, Rectangle r)

假设您想问“这两个列表有哪些共同点?”那么签名就是

List<Point> Intersection(List<Point> l1, List<Point> l2)

等等。更清楚地说明您想要做什么,我们可以帮助您优化该操作。从签名开始。

This code makes no sense to me so it is really hard to say whether you're doing it wrong or not. Odds are good that yes, you're doing it wrong.

Rather than showing the code, try this. Suppose you had a method that did exactly what you want. What would the signature of that method be? Not the body, just the signature.

Suppose for example you want to ask the question "does this list of points contain a particular point?" Then the signature would be

bool Contains(List<Point> list, Point p)

Suppose you want to ask the question "does this list of points contain any point inside this rectangle?" Then the signature would be

bool ContainsAny(List<Point> list, Rectangle r)

Suppose you want to ask the question "what are the points that these two lists have in common?" then the signature would be

List<Point> Intersection(List<Point> l1, List<Point> l2)

and so on. State what you are trying to do more clearly and we can help you optimize that operation. Start with the signature.

长不大的小祸害 2024-08-31 07:57:49

这不是 lambda 的问题,而是你的算法的问题。你从 MinX 循环到 MaxX 是多少?然后您将循环从 MinY 到 MaxY,然后您将循环大约 19,000 条记录。因此,如果 X 循环为 10,y 循环为 10,那么您将进行 19,000*10*10 次调用。情况可能会更糟。

It's not a problem with the lambda, it's a problem with your algorithm. You're looping through from MinX to MaxX which is how many? then you're looping through the same from MinY to MaxY, then you're looping through ~19,000 records. so if the X loop is 10 and the y loop is 10, then you're making 19,000*10*10 calls. It could be a lot worse.

笑红尘 2024-08-31 07:57:49

你的算法效率低下。如果您在同一个列表上进行多次搜索,则需要:

  1. 排序适当地列表(通过您的查找键)。
  2. 使用二分搜索查找正确的记录。

如果内存不是问题并且您希望速度非常快,您的另一个选择是将记录放入 Dictionary 中。设置完成后,这将为您提供最快的访问速度。

Your algorithm is inefficient. If you are doing multiple searches on the same list you need to:

  1. Sort the list appropriately (by your look up key).
  2. Use a binary search to find the right record.

Your other option is if memory isn't an issue and you want it to be really fast is to put the records into a Dictionary<Your_Key,Record>. That will give you the fastest access after you have it setup.

惯饮孤独 2024-08-31 07:57:49

这不是你想要的吗?

myList.Where(
    item=>item.XCoord>=MinX
        &&item.XCoord<=MaxX
        &&item.YCoord>=MinY
        &&item.YCoord<=MaxY
)

所有生成的项目都将满足 exists 标准。

……还是我理解错了?

Isn't this what you want?

myList.Where(
    item=>item.XCoord>=MinX
        &&item.XCoord<=MaxX
        &&item.YCoord>=MinY
        &&item.YCoord<=MaxY
)

All the resulting items will satisfy the exists criterion.

...or did I misunderstand?

白云不回头 2024-08-31 07:57:49

我将用一个很好的基于 linq 的解决方案来扩展 Kevin 的答案。

原始代码有效地计算了一个二维布尔数组,指示在 x 处的 myList 中是否存在坐标。每个数组元素的 y 坐标。

用于每个 x & 的测试y 可以表示为 lambda 函数,如下所示:

Func<int, int, bool> original =
    (x, y) =>
        myList.Exists(item => item.XCoord == x && item.YCoord == y);

这是低效的,因为调用 Exists 方法,因此对于每个 xx 都会迭代列表代码> & y 坐标已测试。是否迭代整个列表取决于是否找到匹配项。在很多情况下,不会有匹配项,因此整个列表会被多次访问。

因此,最好预先计算字典的字典,以确定 myList 中是否存在任何 x & 的坐标。 y 坐标。

var xyLookup =
    (from item in myList
     group item by item.XCoord into XCoords
     select new
     {
         X = XCoords.Key,
         YLookup = (from x in XCoords
                    group x by x.YCoord into YCoords
                    select new
                    {
                        Y = YCoords.Key,
                        Coords = YCoords
                    }).ToDictionary(a => a.Y, a => a.Coords)
     }).ToDictionary(b => b.X, b => b.YLookup);

xyLookup 现在允许以下 lambda 函数替换原始版本。

Func<int, int, bool> refactored =
    (x, y) =>
        xyLookup.ContainsKey(x) && xyLookup[x].ContainsKey(y);

预计算 xyLookup 需要一些时间,因此根据我的测试,如果我有一个 3x3 数组并且 myList 包含 3 个坐标,那么两种方法的速度大致相同。不过,我预计 myList 中的实际数组大小和元素数量在实践中会大得多。

如果我在 myList 中有一个包含 10,000 个坐标的 100x100 数组,则 xyLookup 比原始方法快大约 91 倍。

我喜欢 linq...:-)

I'm going to expand on Kevin's answer with a nice linq-based solution.

The original code effectively computed a two dimensional boolean array indicating if a coordinate existed in myList at the x & y coordinates for each array element.

The test used for each x & y can be expressed as a lambda function as such:

Func<int, int, bool> original =
    (x, y) =>
        myList.Exists(item => item.XCoord == x && item.YCoord == y);

This is inefficient as the Exists method is called, and hence the list is iterated, for each x & y coordinate tested. Whether or not the entire list is iterated over depends if a match is found or not. In a lot of cases there won't be a match so the entire list is visited multiple times.

It is therefore best to pre-compute a dictionary of dictionaries to determine if a coordinate exists in myList for any x & y coordinate.

var xyLookup =
    (from item in myList
     group item by item.XCoord into XCoords
     select new
     {
         X = XCoords.Key,
         YLookup = (from x in XCoords
                    group x by x.YCoord into YCoords
                    select new
                    {
                        Y = YCoords.Key,
                        Coords = YCoords
                    }).ToDictionary(a => a.Y, a => a.Coords)
     }).ToDictionary(b => b.X, b => b.YLookup);

xyLookup now allows the following lambda function to replace the original version.

Func<int, int, bool> refactored =
    (x, y) =>
        xyLookup.ContainsKey(x) && xyLookup[x].ContainsKey(y);

Pre-computing xyLookup takes some time so, according to my tests, if I have a 3x3 array and myList contains 3 coordinates then both methods are roughly the same speed. I would expect, though, that the actual array size and number of elements in myList would be much larger in practice.

If I have a 100x100 array with 10,000 coordinates in myList then xyLookup is approximately 91 times faster than the original method.

I love linq... :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文