获取任何类型的 2D 数组 [,] 中两个项目之间的 x 或 y 距离,不知道任一项目的索引并编辑 [关闭] 之间的项目

问题描述 投票:0回答:2

出于学习目的,我问“任何类型”,但实际上我现在正在处理一个

byte[,]
类型数组,它被称为
byteTable
,其内容如下所示:

 00  01  E1  03  04  05

 06  07 (08) 09  0A  0B

 08  0D  0E  0F  10 (08)

 12  13  14  15  04  17

(08) 19 {1A} 1B  1C  1D

 1E  1F  20  10 (08) 23

括号只是为了便于阅读。我想找到数组中唯一的

1A
字节的索引,然后找到从
08
垂直向上方向最近的非唯一
1A
字节值并获取其距离。之后,我需要将中间的所有字节替换为
FF
字节,包括
1A
字节但不包括
08
字节,然后从
0E
所在的字节顺时针重复此操作。

或者,可以不求距离,而是覆盖所有字节,直到从

08
垂直开始顺时针移动,直到到达
1A
字节。哪种方法更可行?

结果应该是这样的:

enter image description here

 00  FF  E1  03  04  05

 06  FF  08  09  0A  0B

 08  FF  FF  FF  FF  08

 12  FF  FF  15  FF  17

 08  FF  FF  FF  FF  1D

 1E  1F  20  10  08  23
c# arrays matrix multidimensional-array
2个回答
0
投票

既然你正在学习,我不会给你完整的解决方案,而是给你一些提示。


您可以使用两个嵌套的 for 循环来查找 1A 值。一个循环在 x 上循环,另一个在 y 上循环。在单独的函数中实现它更容易,因为这样您可以简单地使用

return
语句来停止循环并返回结果。

您可以使用元组返回 x 和 y 索引:

(int x, int y)

参见:元组类型(C# 参考)


您需要一种方法来定义四个基本方向。一种可能的方法是在像这样的元组数组中声明移动方向的 delta x 和 y 值(我正在向下定义正 y 方向。如果您以相反的方式执行此操作,则必须更改

dy
的符号):

//                                 up     right    down    left
(int dx, int dy)[] directions = [(0, -1), (1, 0), (0, 1), (-1, 0)];

然后您可以使用模运算符

%
循环方向来限制索引,如下所示

int direction = 0; // upwards

// In the main loop
(int dx, int dy) = directions[direction];
direction = (direction + 1) % 4;

您可以在主循环中使用此代码来确定方向,并使用嵌套内循环通过分别将

dx
dy
添加到
x
y
来执行直线移动。

当到达边界或 08 时,内部循环结束。

当到达取决于移动方向的边界时,主循环结束。例如。当 dx 为 -1 时,x == 0 是边框,当 dx = 1 时,x == width_of_the_array - 1 是边框,等等

当然,您可以使用冗长的布尔表达式或一系列 if 语句以经典方式确定此条件,或者您可以使用非常先进的技术,使用 Lambda 表达式

为此,我们将通过代表边界条件的委托来扩展方向数组的元组:

(int dx, int dy, Func<int, int, bool> isBorder)[] directions = [
    ( 0, -1, (ix, iy) => iy <= 0),
    ( 1,  0, (ix, iy) => ix >= Width - 1),
    ( 0,  1, (ix, iy) => iy >= Height - 1),
    (-1,  0, (ix, iy) => ix <= 0)
];

然后您可以使用

获取方向相关参数
var (dx, dy, isBorder) = directions[direction];

然后您可以使用

if (isBorder(x, y)) { ... }
检查边界条件。

这意味着您不需要计算距离,只需循环直到达到条件。例如

while (true) { // endless inner loop
    if (byteTable[x, y] == 0x08) {
        break; // end the inner loop and let the outer loop turn around clockwise
    }
    byteTable[x, y] = 0xFF;
    if (a border is reached) {
        return; // end the algorithm and print out the solution.
    }
}

您还询问是否允许任何数组元素类型。 C# 有所谓的泛型。请参阅:通用类和方法

它们允许您用泛型类型替换真实类型。例如。您可以用通用方法包装您的解决方案:

public static void Solve<T>(T[,] table, T uniqueStartValue, T wayMark)
{
    // where wayMark corresponds to the 08 byte
    ...
}

请注意,您不能将

a == b
应用于泛型类型。您必须使用
a.Equals(b)
比较两个值。


我承认我使用了很多非常先进的东西。但是您当然可以使用涉及更多代码的更简单的方法。您可以为四个基本方向中的每个方向编写四段不同的代码,而不是使用方向数组(带有元组和 lambda)。

此外,您不需要从一开始就找到所有问题的解决方案。小步前进并慢慢改进解决方案,直到一切正常。假设这是一个控制台应用程序,

PrintTable(byteTable)
方法非常有用,不仅可以打印最终结果,还可以调试以打印循环内的中间状态,以便您可以观察算法如何进行(以及哪里失败) .


0
投票

首先,您必须找到 1A 字节的 2d 索引。然后,您需要迭代索引,直到找到 08 字节,转动它,然后重复,直到到达数组的边缘。

public static class ArrayExtensions
{
    // Find index of an element in a 2d array
    public static (int x, int y) CoordinateOf<T>(this T[,] array, T value)
    {
        for (int x = 0; x < array.GetLength(0); ++x)
        {
            for (int y = 0; y < array.GetLength(1); ++y)
            {
                if (array[x, y]?.Equals(value) == true)
                    return (x, y);
            }
        }

        return (-1, -1);
    }

    // Do the Stuff op asked
    public static void DoStuff(this byte[,] array)
    {
        // Declare variables
        var pos = array.CoordinateOf<byte>(0x1A);
        var dir = (x: -1, y: 0); // Because 2d arrays are weird, this is 'up'
        var width = array.GetLength(0);
        var height = array.GetLength(1);

        // Move the position an initial step
        pos.x += dir.x;
        pos.y += dir.y;

        // Cache the starting position
        var start = pos;

        // Loop until we cross the edge of the array
        while (pos.x >= 0 && pos.x < width
            && pos.y >= 0 && pos.y < height)
        {
            if (array[pos.x, pos.y] == 0x08)
            {
                // If the element is 0x08, turn clockwise
                pos.x -= dir.x;
                pos.y -= dir.y;

                dir = (dir.y, -dir.x);
            }
            else
                array[pos.x, pos.y] = 0xFF; // Set 0xFF

            // Add direction to position
            pos.x += dir.x;
            pos.y += dir.y;

            if (pos.x == start.x && dir.x == 0
                && pos.y == start.y && dir.y == -1)
                break; // prevent infinite loop
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.