F#Manhatten 2 Array2D之间的距离

时间:2014-05-07 11:25:45

标签: arrays f# distance

所以我有两块电路板,例如

let startingBoard = [|[|1; 4; 7|];
                     [|6; 3; 5|];
                     [|0; 8; 2|]|]

let goal = [|[|1; 2; 3|];
            [|4; 5; 6|];
            [|7; 8; 0|]|]

并且希望找到两个阵列之间相似元素的所有曼哈顿距离的总和(例如,4个瓦片的曼哈顿距离将是2个向下移动,向左移动一个)我到目前为止所有的代码都是代码在其下方找到给定的索引的曼哈顿距离。

let totalManhattenDistance board goal =
    let manhattenDistance (x1, y1) (x2, y2) =
        abs(x1 - x2) + abs(y1 - y2)
// solution here

问题是我无法想象没有for循环这样做,但这似乎是单一的。

4 个答案:

答案 0 :(得分:2)

这是一个版本

let totalManhattanDistance board goal =
    let manhattanDistance ((x1, y1), (x2, y2)) = abs(x1 - x2) + abs(y1 - y2)
    let indexed xs = xs |> Seq.mapi (fun i -> Seq.mapi (fun j x -> (i, j), x))
                        |> Seq.concat
                        |> Seq.sortBy snd
                        |> Seq.map fst
    Seq.zip (indexed board) (indexed goal)
    |> Seq.map manhattanDistance
    |> Seq.sum

最后三个Seq操作只能用一个Array.fold2完成,但我不知道这是否使代码更清晰

let totalManhattanDistance board goal =
    let manhattanDistance (x1, y1) (x2, y2) = abs(x1 - x2) + abs(y1 - y2)
    let indexed xs = xs |> Array.mapi (fun i -> Array.mapi (fun j x -> (i, j), x))
                        |> Array.concat
                        |> Array.sortBy snd
                        |> Array.map fst
    let folder = fun acc n m -> acc + manhattanDistance n m
    Array.fold2 folder 0 (indexed board) (indexed goal)

答案 1 :(得分:1)

使用2D阵列问题接缝更自然:

let startingBoard = array2D [|[|1; 4; 7|];
                             [|6; 3; 5|];
                             [|0; 8; 2|]|]

let goal = array2D [|[|1; 2; 3|];
                    [|4; 5; 6|];
                    [|7; 8; 0|]|]

不幸的是没有findIndex2D函数(比如Array.findIndex)。你必须自己定义:

let findIndex2D (p:'A -> bool) (a:'A [,]) =
  a |> Array2D.mapi (fun x y v -> x,y,v)
    |> Seq.cast<int*int*'A>
    |> Seq.pick (fun (x,y,v) -> if p v then Some (x,y)  else None)

直接定义曼哈顿距离:

let manhattanDistance (x1, y1) (x2, y2) = abs(x1 - x2) + abs (y1 - y2)

所有曼哈顿距离的总和:

let totalManhattanDistance board goal =
  board |> Array2D.mapi (fun x y v -> manhattanDistance (x, y)
                                        <| findIndex2D ((=) v) goal)
        |> Seq.cast<int>         // flatten
        |> Seq.reduce (+)

答案 2 :(得分:0)

另一个版本:

let newpos (start : int[][]) (finish:int[][]) (i, j) = 
    let rw = 
        finish |> Array.fold (fun (found, y, x) row -> 
            if found then (found, y, x)
            else
                match row |> Array.tryFindIndex ((=) start.[i].[j]) with 
                | Some nX -> (true, y, nX) 
                | None -> (false, y+1, x)
        ) (false, 0, 0)

    match rw with
    | (true, x, y) -> (x, y)
     | _ -> failwith "Not found"

let totalManhattenDistance board goal =
    let manhattenDistance (x1, y1) (x2, y2) = abs(x1 - x2) + abs(y1 - y2)

    board |> Array.mapi (fun i arr ->
        arr |> Array.mapi (fun j v ->
            let (i1, j1) = newpos board goal (i, j)
            manhattenDistance (i, j) (i1, j1)
        )
    )

totalManhattenDistance startingBoard goal

答案是

val it : int [] [] = 
[|[|0; 2; 4|]; 
   [|2; 2; 1|]; 
   [|2; 0; 3|]|]

答案 3 :(得分:0)

这是一个F#惯用(我希望)的版本,与mikkoma的版本不太相似:

let flatten a2D =
    a2D |> Array.mapi (fun i1 a1D -> a1D
        |> Array.mapi (fun i2 el -> (el, (i1, i2)) ))
        |> Array.concat |> Array.sortBy fst

let manhattan b1 b2 =
    flatten b1
        |> Array.zip (flatten b2)
        |> Array.sumBy (fun ((_, (i1, j1)), (_, (i2, j2))) -> abs(i2-i1) + abs(j2-j1))

flatten将2D数组转换为一维数组,其中每个元素都放在棋盘上的坐标旁边。
manhattan然后简单地将2个1D阵列拉到一起并总结坐标偏移量。