遍历F#2D数组

遍历F#2D数组,f#,F#,我正在用F#创建一个棋盘(类型)游戏,在以“功能”方式遍历数组时遇到了一些问题 例如,我有一个数组,看起来像: val myArray : int [,] = [[1; 1; 0; 0; 0] [0; 0; 1; 0; 0] [2; 0; 0; 0; 3] [0; 0; 0; 0; 0] [0; 1

我正在用F#创建一个棋盘(类型)游戏,在以“功能”方式遍历数组时遇到了一些问题

例如,我有一个数组,看起来像:

val myArray : int [,] = [[1; 1; 0; 0; 0]
                         [0; 0; 1; 0; 0]
                         [2; 0; 0; 0; 3]
                         [0; 0; 0; 0; 0]
                         [0; 1; 0; 0; 1]]
我想基于上述内容创建一个新阵列,其中:

  • 如果项大于0,则新数组中的数字应为1
  • 如果项目为=0,则:
  • 如果左侧、右侧、上方或下方的项目>1,则在新数组中,数字应为2
  • 否则,如果右侧左侧、上方或下方的项目=1,则在新数组中,数字应为3
  • 否则,数字应为4
  • 这将创建一个新数组,如下所示:

    val myArray : int [,] = [[1; 1; 3; 4; 4]
                             [2; 3; 1; 3; 2]
                             [1; 2; 3; 2; 1]
                             [2; 3; 4; 4; 2]
                             [3; 1; 3; 3; 1]]
    
    我看不出有什么简单的方法可以做到这一点。在C#中,我只想为循环创建一个
    ,但我认为在F#中可能会有一种偷偷摸摸的方法,使用
    映射
    函数-
    映射
    看起来很有希望,但它似乎只能访问当前正在考虑的片段及其索引,而不是整个数组


    我的问题似乎是游戏规则取决于周围区域,而标准的遍历方法似乎不允许访问周围区域-实现我所做的事情的最佳方式是什么?

    我不认为我在这个解决方案中耍了什么鬼把戏。我使用Array2D.init构建了一个新的数组。init所需的函数确定每个位置的数组值

    此外,我将收集邻居放在一个单独的函数中。在邻居函数中,我使用了列表理解,只生成有效的邻居,避免了角落和边缘的麻烦

    这就是我想到的(警告:当2D数组为1x1或为空时,它将失败,我将把它留给读者以防出现这种情况):

    结果:

    val result : int [,] = [[1; 1; 3; 4; 4]
                            [2; 3; 1; 3; 2]
                            [1; 2; 3; 2; 1]
                            [2; 3; 4; 4; 2]
                            [3; 1; 3; 3; 1]]
    
    我的一些想法:

    阵列设计为通过索引进行访问。如果使用数组存储数据,那么通过索引访问它是最方便的方法

    您需要的是一个数据结构,其中一个元素知道它的邻居在哪里。此数据结构不是一个简单的数组。您可以通过扩充阵列来设计这样的数据结构:

    type NArray(A: int [,]) = 
        member x.Item with get (i,j) = (A.[i,j], i, j, A)
    
    您还可以将四个相邻元素显式添加到元素:

    type NArray(A: int [,]) = 
        let get i j di dj = 
            let newI = i + di
            let newJ = j + dj
            if newI < 0 || newI > A.GetLength(0) then None
            elif newJ < 0 || newJ > A.GetLength(1) then None
            else Some (A.[newI, newJ])
    
        member x.Item with get (i,j) = (A.[i,j], get i j 0 1, get i j 0 -1, get i j 1 0, get i j -1, 0)
    
    输入NArray(A:int[,])=
    让我们得到i j di dj=
    设newI=i+di
    设newJ=j+dj
    如果newI<0 | | newI>A.GetLength(0),则无
    elif newJ<0 | | newJ>A.GetLength(1)则无
    其他一些(A.[newI,newJ])
    成员x.具有get(i,j)=(A[i,j],get ij01,get ij0-1,get ij10,get ij-1,0)的项
    
    当您希望序列或列表知道其邻居时,也会出现同样的问题。他们被设计成不知道。如果列表中的元素知道其上一个节点,那么它就不再是单个链接列表


    当您选择数据结构时,您继承了它的优点和缺点。对于数组,您可以获得快速索引,而它的元素本身没有位置的概念。其他数据结构,比如线程二叉树或双链表,它们的元素知道它们在哪里。但成本是使用了更多的存储空间

    这看起来和我需要的一模一样,更像是F#而不是我创造的。。。虽然我的解决方案非常相似,但我创建了一个新的数组,其中满是零,然后有一个嵌套的for循环来遍历原始数组。我也没有使用列表理解的东西,所以我可能一点也不接近这一点来想想。。。
    type NArray(A: int [,]) = 
        member x.Item with get (i,j) = (A.[i,j], i, j, A)
    
    type NArray(A: int [,]) = 
        let get i j di dj = 
            let newI = i + di
            let newJ = j + dj
            if newI < 0 || newI > A.GetLength(0) then None
            elif newJ < 0 || newJ > A.GetLength(1) then None
            else Some (A.[newI, newJ])
    
        member x.Item with get (i,j) = (A.[i,j], get i j 0 1, get i j 0 -1, get i j 1 0, get i j -1, 0)