首页 > 解决方案 > 从 for 循环返回 false 否则在 F# 中继续

问题描述

我出于专业目的学习 F#。我知道 Python/Django 和 C#/.NET Core。所以我想把我用 Python 写的一些代码翻译成 F#。我挂断了电话,或者只是很累,不确定,我想我可以进行一些合作。我想这样做,else continue但发现那不是一个选择。原始python代码:

#!/Users/ryandines/.local/share/virtualenvs/netcoreapp2.0-5nmzfUwt/bin/python

NUMBER_OF_TESTS = input()

INT_MIN = -2**32

def can_represent_bst(pre):
    stack = []
    root = INT_MIN
    for value in pre:
        if value < root:
            return False
        while(stack and stack[-1] < value):
            root = stack.pop()

        stack.append(value)

    return True

for test in range(int(NUMBER_OF_TESTS)):
    node_count = int(input())
    nodes = list(map(int, input().split(' ')))
    print("NODES: " + str(nodes))
    if can_represent_bst(pre=nodes):
        print("YES")
    else:
        print("NO")

到目前为止,这就是我在 F# 中编译和工作的结果:

open System
let NumberOfTests = Console.ReadLine() |> int
let root = Int32.MinValue
let seq1 = seq { for i in 0 .. NumberOfTests-1 -> (i, i*i) }

let CanRepresentBST args =
    printfn "Passed args: %s" args
    let result = args.Split ' '
    let IntList = [for i in result -> i |> int32]
    for value in IntList do
        printfn "%d" value

[<EntryPoint>]
let main argv =
    printfn "Hello World from F#!"    
    printfn "Number of tests: %d" NumberOfTests   
    printfn "Int min value: %d" root

    for _ in seq1 do
        let NodeCount = Console.ReadLine()
        let Nodes = Console.ReadLine()
        printfn "NodeCount: %s" NodeCount      
        let _ = CanRepresentBST Nodes
        0 |> ignore

    0

未完成的部分是这样的:

    if value < root:
        return False
    while(stack and stack[-1] < value):
        root = stack.pop()

    stack.append(value)

可能会睡在上面,但如果有人为我做繁重的工作,我会很高兴,这样我醒来时就可以把它敲掉。

标签: pythonf#

解决方案


这是一个部分解决方案(因为它尝试复制 Python,而不是正确使用 F#):

open System
let NumberOfTests = Console.ReadLine() |> int

let rec getNewRoot value stack root =
    let mutable newRoot = root
    let mutable acc = stack
    while not (List.isEmpty acc) && (List.head acc) < value do
       newRoot <- List.head acc
       acc <- List.tail acc

    (newRoot, acc)

let CanRepresentBST args baseRoot =
    printfn "Passed args: %s" args
    let intList = args.Split ' ' |> Seq.map int |> Seq.toList
    let rec subfunc rem acc root =
        match rem with
        | [] -> true
        | r :: rs ->
            if r < root then
                false
            else
                let (newRoot, newAcc) = getNewRoot r acc root
                subfunc rs (r :: newAcc) newRoot

    subfunc intList [] baseRoot

printfn "Number of tests: %d" NumberOfTests
let root = Int32.MinValue
printfn "Int min value: %d" root

for _ in 1..NumberOfTests do
    let NodeCount = Console.ReadLine()
    let Nodes = Console.ReadLine()
    printfn "NodeCount: %s" NodeCount
    if CanRepresentBST Nodes root then
        printfn "YES"
    else
        printfn "NO"

我将其更改为 fsx 交互式脚本以使其更易于测试(使用fsi filename.fsx运行它),但我认为将其转换回已编译的程序应该很容易。

请注意,由于 getNewRoot 函数,许多(如果不是大多数)F# 粉丝不会喜欢这个程序 - 那里有太多的可变性。

我将 root 的定义移到程序的末尾,并让 CanRepresentBST 将其作为参数,以使函数成为纯函数 - 如果您总是以 MinValue 作为 root 开始,您可以在 CanRepresentBST 的顶部声明它。CanRepresentBST 现在使用一个辅助子函数(无用的命名 subfunc),它为输入列表的剩余部分、累积的“堆栈”和当前根值获取参数。然后它递归地处理输入列表,像以前一样返回 false,在列表末尾返回 true,或者使用尾递归调用正常处理它。

getNewRoot 用于封装根值的更新和累加栈的调整。

请注意,这是对 Python 的相当接近的翻译,这就是它膨胀得如此之多的原因。更好的办法是回到您想要实现的目标的本质,并使用您在 F# 中所拥有的东西编写新的东西。如果其他人想发布更好的版本,请这样做!


推荐阅读