powershell - 嵌套循环抽象

标签 powershell recursion

这是一组嵌套的for循环的简单方法,其中最大变量值分别为1、2和3:

for ($i = 0; $i -le 1; $i++)
{
    for ($j = 0; $j -le 2; $j++)
    {
        for ($k = 0; $k -le 3; $k++)
        {
            "$i $j $k"
        }
    }
}

我想要一个抽象,用于指示任意数量的嵌套for循环。因此,例如,以上将被调用为:
NestedForLoops (1, 2, 3) { Param($i, $j, $k) "$i $j $k" }

这是一种基于this answer的方法:
function NestedForLoopsAux([int[]]$max_indices, [int[]]$indices, [int]$index, $func)
{
    if ($max_indices.Count -eq 0) { &($func) $indices }
    else
    {
        $rest = $max_indices | Select-Object -Skip 1

        for ($indices[$index] = 0; $indices[$index] -le $max_indices[0]; $indices[$index]++)
        { NestedForLoopsAux $rest $indices ($index + 1) $func }
    }
}

function NestedForLoops([int[]]$max_indices, $func)
{
    NestedForLoopsAux $max_indices (@(0) * $max_indices.Count) 0 $func
}

示例调用:
PS C:\> NestedForLoops (1, 2, 3) { Param([int[]]$indices); $i, $j, $k = $indices; "$i $j $k" }
0 0 0
0 0 1
0 0 2
0 0 3
0 1 0
0 1 1
0 1 2
0 1 3
0 2 0
0 2 1
0 2 2
0 2 3
1 0 0
1 0 1
1 0 2
1 0 3
1 1 0
1 1 1
1 1 2
1 1 3
1 2 0
1 2 1
1 2 2
1 2 3

有没有更好的办法?

最佳答案

我不知道这是否更容易,但是您可能会认为这是为您提供更多选择的一种方式。逻辑的核心是构建将用Invoke-Expression执行的代码字符串。通常只是想看看我是否能做到。

Function New-ForLoopBlock{
    Param(
        [char]$variableLetter,    # {0} Index varialble
        [int]$baseIndex,          # {1} Base Index Value
        [int]$indexMaximum        # {2} Max Index Value
    )
    "for (`${0} = {1}; `${0} -le {2}; `${0}++)" -f $variableLetter,$baseIndex,$indexMaximum
}


Function LoopDeLoop{
    Param(
        [int[]]$maximums,
        [int]$baseIndex = 0 
    )

    # Build a small hashtable with variable and array values.
    $values = @{}
    For($letterIndex = 0; $letterIndex -lt $maximums.Count; $letterIndex++){
        New-Variable -Force -Name [char]($letterIndex + 65)
        $values.([char]($letterIndex + 65)) = $maximums[$letterIndex]
    }

    $nestedLoops = "{}"
    # Build the for loop
    $nestedLoops = $values.GetEnumerator() | Sort-Object Name | ForEach-Object{
        "$(New-ForLoopBlock $_.Name $baseIndex $_.Value){"
    }

    # The output string this exists inside the loop
    $outputString = [string]($values.GetEnumerator() | Sort-Object Name | ForEach-Object{"`$$($_.Name)"})

    # Add the output string and closing braces
    $nestedLoops = "$nestedLoops`r`n`"$outputString`"`r`n$("}" * $maximums.Count)"

    Invoke-Expression $nestedLoops
}
LoopDeLoop接受2个参数。就像您的整数数组和可选的基值一样。为$maximums中的每个数组元素创建一些变量(形式为$ a,$ b,....),这些变量将表示每个for循环的索引值。

然后使用$nestedLoops的输出来创建字符串New-ForLoopBlock字符串。它不需要是一个函数,而只是返回一个包含for循环语句的字符串。在早期的迭代中,存在更多的逻辑。

然后,我们需要构建小的输出字符串。在您的示例中,这是“$ i $ j $ k”。我的是根据创建的变量数量构建的。

在字符串的结尾,我们用大括号关闭for循环。 $nestedloops的示例如下:
for ($A = 2; $A -le 3; $A++){ for ($B = 2; $B -le 3; $B++){ for ($C = 2; $C -le 4; $C++){
"$A $B $C"
}}}

就格式化而言,它看起来很糟糕,但是代码具有100%的功能。现在,让我们看一下该函数的一些示例输出:
LoopDeLoop (3,3,4) 2
2 2 2
2 2 3
2 2 4
2 3 2
2 3 3
2 3 4
3 2 2
3 2 3
3 2 4
3 3 2
3 3 3
3 3 4

关于powershell - 嵌套循环抽象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27938366/

相关文章:

sql-server - Powershell SQLServer 模块

azure - 如何检查特定的 Azure ARM 资源是否存在,如果不存在则使用 PowerShell 创建它

performance - 如何衡量循环方法和递归方法之间代码速度的差异?

c - 从 C 中的列表的递归组合中打印

java - 递归插入到双向链表的末尾

c++ - 如何在二叉树遍历C++的末尾添加一个新行

powershell - 在 Powershell 中创建文件夹和文件

powershell - 重复将一个文件的内容复制到另一个文件

powershell - 使用 powershell 在远程计算机上运行的进程的开始时间

c++ - 如果未指定返回类型,递归 lambda 将无法编译