避免C#数组中重复操作的最有效方法是什么?

时间:2012-05-14 12:15:21

标签: c# arrays

我需要计算数组中每对点之间的距离,并且每个对只想做一次。我能提出足够的效率还是有更好的方法?这是一个例子,还有一个视觉来解释我想要获得的东西:

diagram of code purpose

例如,首先得到段A-B,A-C,A-D;那么B-C,B-D;最后,C-D。换句话说,我们想要A-B在我们的新阵列中,但不是B-A,因为它会是重复的。

var pointsArray = new Point[4];

pointsArray[0] = new Point(0, 0);
pointsArray[1] = new Point(10, 0);
pointsArray[2] = new Point(10, 10);
pointsArray[3] = new Point(0, 10);

// using (n * (n-1)) / 2 to determine array size
int distArraySize = (pointsArray.Length*(pointsArray.Length - 1))/2;

var distanceArray = new double[distArraySize];

int distanceArrayIndex = 0;

// Loop through points and get distances, never using same point pair twice
for (int currentPointIndex = 0; currentPointIndex < pointsArray.Length - 1; currentPointIndex++)
{
    for (int otherPointIndex = currentPointIndex + 1;
            otherPointIndex < pointsArray.Length;
            otherPointIndex++)
    {
        double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X;
        double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y;

        double distance = Math.Sqrt(Math.Pow(xDistance, 2) + Math.Pow(yDistance, 2));

        // Add distance to distanceArray
        distanceArray[distanceArrayIndex] = distance;

        distanceArrayIndex++;
    }
} 

由于这将使用数千个点,我认为精确尺寸的数组比使用任何类型的IEnumerable更有效。

4 个答案:

答案 0 :(得分:3)

如果你有n个点,则所有点对的集合包含n *(n-1)/ 2个元素。这就是您正在进行的操作数量。我要做的唯一改变是使用Parallel.ForEach()并行执行操作。

像这样(需要调试)

        int distArraySize = (pointsArray.Length * (pointsArray.Length - 1)) / 2;

        var distanceArray = new double[distArraySize];

        int numPoints = pointsArray.Length;

        Parallel.ForEach<int>(Enumerable.Range(0, numPoints - 2),
            currentPointIndex =>
            {
                Parallel.ForEach<int>(Enumerable.Range(currentPointIndex + 1, numPoints - 2),
                    otherPointIndex =>
                    {
                        double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X;
                        double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y;
                        double distance = Math.Sqrt(xDistance * xDistance + yDistance * yDistance);
                        int distanceArrayIndex = currentPointIndex * numPoints - (currentPointIndex * (currentPointIndex + 1) / 2) + otherPointIndex - 1;
                        distanceArray[distanceArrayIndex] = distance;
                    });
            });

答案 1 :(得分:0)

过去我必须执行这样的操作,而且我认为您对高数字紧缩操作的直接反应是“必须有更快或更有效的方法来执行此操作”。 我能想到的唯一其他可以远程操作的解决方案是散列对并将此哈希放在HashSet中,然后在进行距离计算之前检查HashSet。但是,这可能最终会导致性能下降。

你的解决方案很好。正如j0aqu1n指出的那样,你可能不得不以这种或那种方式处理这些数字,在这种情况下,你不会两次执行相同的计算。

看看是否有其他解决方案将会很有趣。

答案 2 :(得分:0)

对我来说很好,但你有没有错误?

除了第一个位置外,每个内部迭代几乎完全覆盖前一个迭代。不是吗?

也就是说,在distanceArray[otherPointIndex]其他PointIndex获取从currentPointIndex + 1pointsArray.Length - 1的值。
在您的示例中,这将在[0-3]而不是[0-6]范围内。

答案 3 :(得分:0)

我认为,使用xDistance*xDistance代替Math.Pow(xDistance, 2)要快一些。 除此之外,如果你真的总是需要计算所有距离,那么就没有太大的改进空间了。 如果,OTOH,你有时不需要计算所有,你可以在需要时懒洋洋地计算距离。