【问题标题】:Get all combinations of an array获取数组的所有组合
【发布时间】:2014-08-27 05:57:24
【问题描述】:

我目前正在尝试制作一个函数来获取数组值的所有可能组合。

我想出了一个非函数版本,但它被限制为 3 个值,所以我试图用它制作一个函数以变得更多 Dynamic

我尝试搜索 SO,但找不到我想要做的事情的 powershell 示例,我可以找到一个 PHP 版本,但我的 PHP 非常有限

PHP: How to get all possible combinations of 1D array?

非功能脚本

$name = 'First','Middle','Last'

$list = @()

foreach ($c1 in $name) {
    foreach ($c2 in $name) {
        foreach ($c3 in $name) {
            if (($c1 -ne $c2) -and ($c2 -ne $c3) -and ($c3 -ne $c1))
            {
                $list += "$c1 $c2 $c3"
            }
        }
    }
} 

这给了我结果

First Middle Last
First Last Middle
Middle First Last
Middle Last First
Last First Middle
Last Middle First

我不确定在递归函数时如何重新排列这些值,这就是我目前所拥有的:

<#
.Synopsis
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
.EXAMPLE
    Another example of how to use this cmdlet
#>
function Get-Combinations
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string[]]$Array,

        # Param1 help description
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$false,
                   Position=1)]
        [string]$Temp,

        # Param1 help description
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   Position=2)]
        [string[]]$Return
    )

    Begin
    {
        Write-Verbose "Starting Function Get-Combinations with parameters `n`n$($Array | Out-String)`n$temp`n`n$($Return | Out-String)"

        If ($Temp)
        {
            $Return = $Temp
        }

        $newArray = new-object system.collections.arraylist
    }
    Process
    {
        Write-Verbose ($return | Out-String)

        For($i=0; $i -lt $Array.Length; $i++)
        {
            #Write-Verbose $i

            $Array | ForEach-Object {$newArray.Add($_)}
            $newArray.RemoveAt($i)

            Write-Verbose ($newArray | Out-String)

            if ($newArray.Count -le 1)
            {
                Get-Combinations -Array $newArray -Temp $Temp -Return $Return
            }
            else
            {
                $Return = $Temp
            }
        }
        $newArray
    }
    End
    {
        Write-Verbose "Exiting Function Get-Combinations"
    }
}

$combinations = @("First","First2","Middle","Last")

$Combos = Get-Combinations -Array $combinations

$Combos

但是我得到的输出到处都是

First2
Last
First2
Last
First
First2
Middle
Last
First
First2
Middle
Last

28/08 更新

越来越近,但仍然得到奇怪的输出

<#
.Synopsis
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
.EXAMPLE
    Another example of how to use this cmdlet
#>
function Get-Combinations
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                    ValueFromPipelineByPropertyName=$true,
                    Position=0)]
        [string[]]$Array,

        # Param1 help description
        [Parameter(Mandatory=$false,
                    ValueFromPipelineByPropertyName=$false,
                    Position=1)]
        [string]$Temp,

        # Param1 help description
        [Parameter(Mandatory=$false,
                    ValueFromPipelineByPropertyName=$true,
                    Position=2)]
        [string[]]$Return
    )

    Begin
    {
        Write-Verbose "Starting Function Get-Combinations with parameters `n`n$($Array | Out-String)`n$temp`n`n$($Return | Out-String)"

        If ($Temp)
        {
            $Return += $Temp
        }

        #$newArray = new-object [System.Collections.ArrayList]
        #$Array | ForEach-Object {$newArray.Add($_) | Out-Null}

        [System.Collections.ArrayList]$newArray = $Array
    }
    Process
    {
        Write-Verbose "return -> $return"

        For($i=0; $i -lt $Array.Length; $i++)
        {
            Write-Verbose "`$i -> $i"

            $element = $newArray[0]
            $newArray.RemoveAt(0)

            Write-Verbose "`$newArray -> $newArray"
            Write-Verbose "Element -> $element"

            if ($newArray.Count -gt 0)
            {
                Get-Combinations -Array $newArray -Temp (($temp + " " +$element).Trim()) -Return $Return
            }
            else
            {
                $Return = $Temp + " " + $element
            }
        }
        $return
    }
    End
    {
        Write-Verbose "Exiting Function Get-Combinations"
    }
}

$combinations = @("First","First2","Middle","Last")

$return = @()

$Combos = Get-Combinations -Array $combinations -Return $return

$Combos

新输出(是的,'Last' 值之前有一个空格,不,我不知道为什么)

First First2 Middle Last
First First2 Last
First Middle Last
First Last
First2 Middle Last
First2 Last
Middle Last
 Last

【问题讨论】:

  • 所以你想包含 1..$arr.count 结果?如'First'有效,还有'First,First2'和'First,First2,Middle'和'First,First2,Middle,Last'及其所有组合。对吗?

标签: arrays function powershell


【解决方案1】:

这是我的解决方案:

function Remove ($element, $list)
{
    $newList = @()
    $list | % { if ($_ -ne $element) { $newList += $_} }

    return $newList
}


function Append ($head, $tail)
{
    if ($tail.Count -eq 0)
        { return ,$head }

    $result =  @()

    $tail | %{
        $newList = ,$head
        $_ | %{ $newList += $_ }
        $result += ,$newList
    }

    return $result
}


function Permute ($list)
{
    if ($list.Count -eq 0)
        { return @() }

    $list | %{
        $permutations = Permute (Remove $_ $list)
        return Append $_ $permutations
    }
}

cls

$list = "x", "y", "z", "t", "v"

$permutations = Permute $list


$permutations | %{
    Write-Host ([string]::Join(", ", $_))
}

编辑:在一个功能中相同(置换)。这有点作弊,但是因为我用 lambdas 替换了普通函数。您可以将递归调用替换为您自己处理的堆栈,但这会使代码变得不必要地复杂......

function Permute ($list)
{
    $global:remove = { 
        param ($element, $list) 

        $newList = @() 
        $list | % { if ($_ -ne $element) { $newList += $_} }  

        return $newList 
    }

    $global:append = {
        param ($head, $tail)

        if ($tail.Count -eq 0)
            { return ,$head }

        $result =  @()

        $tail | %{
            $newList = ,$head
            $_ | %{ $newList += $_ }
            $result += ,$newList
        }

        return $result
    }

    if ($list.Count -eq 0)
        { return @() }

    $list | %{
        $permutations = Permute ($remove.Invoke($_, $list))
        return $append.Invoke($_, $permutations)
    }
}

cls

$list = "x", "y", "z", "t"

$permutations = Permute $list

$permutations | %{
    Write-Host ([string]::Join(", ", $_))
}

【讨论】:

  • 有一些跳出框框的想法。这是一种非常酷的方法,有没有办法将它浓缩成一个函数?
  • 查看我的编辑。正如我所说,这有点作弊。但我能想到的所有其他替代方案都会使代码更加复杂。
  • 您先生是一位绅士和学者,非常感谢您的编辑。这将给我很多东西,以提高我对递归的了解。
【解决方案2】:

我试图学习一些新东西并帮助你,但我卡住了。也许这会帮助您朝着正确的方向前进,但我对 Powershell 递归的了解还不够,无法弄清楚这一点。我将php转换为powershell,理论上它应该可以工作,但它没有。

$array = @('Alpha', 'Beta', 'Gamma', 'Sigma')


function depth_picker([system.collections.arraylist]$arr,$temp_string, $collect)
{
if($temp_string -ne ""){$collect += $temp_string}
    for($i = 0; $i -lt $arr.count;$i++)
    {
    [system.collections.arraylist]$arrCopy = $arr
    $elem = $arrCopy[$i]
    $arrCopy.removeRange($i,1)
    if($arrCopy.count -gt 0){
    depth_picker -arr $arrCopy -temp_string "$temp_string $elem" -collect $collect}
    else{$collect += "$temp_string $elem"}
    }
}
$collect = @()
depth_picker -arr $array -temp_string "" -collect $collect
$collect

它似乎有效,并且会为您提供第一组可能:

Alpha
Alpha Beta
Alpha Beta Gamma
Alpha Beta Gamma Sigma

但由于某种原因,我无法弄清楚它何时返回到以前的函数并执行 $i++ 然后检查 ($i -lt $arr.count) $arr.count 它始终为 0,因此它永远不会进入下一个函数迭代以继续寻找可能性。

希望其他人可以解决我似乎无法弄清楚的问题,因为我对递归知之甚少。但似乎每个深度级别都称为先前的深度级别 $arr 变量和值丢失了。

【讨论】:

  • 是的,我明白你的意思,这让我很头疼,但我时不时地慢慢靠近,所以至少我明白了。
【解决方案3】:

这是我使用递归函数的解决方案。它生成空格分隔的字符串,但使用 $list[$i].split(" ") 分割每个元素非常简单:

function Get-Permutations 
{
    param ($array, $cur, $depth, $list)

    $depth ++
    for ($i = 0; $i -lt $array.Count; $i++)
    {
        $list += $cur+" "+$array[$i]        

        if ($depth -lt $array.Count)
        {
            $list = Get-Permutations $array ($cur+" "+$array[$i]) $depth $list
        }       
    }

    $list
}    

$array = @("first","second","third","fourth")
$list = @()
$list = Get-Permutations $array "" 0 $list

$list

【讨论】:

    【解决方案4】:

    Micky Balladelli 发布的解决方案几乎对我有用。这是一个不重复值的版本:

    Function Get-Permutations 
    {
        param ($array_in, $current, $depth, $array_out)
        $depth++
        $array_in = $array_in | select -Unique
        for ($i = 0; $i -lt $array_in.Count; $i++)
        {
            $array_out += ($current+" "+$array_in[$i]).Trim()
            if ($depth -lt $array_in.Count)
            {
                $array_out = Get-Permutations $array_in ($current+" "+$array_in[$i]) $depth $array_out
            }
            else {}
        }
        if(!($array_out -contains ($array_in -Join " "))) {}
        for ($i = 0; $i -lt $array_out.Count; $i++)
        {
            $array_out[$i] = (($array_out[$i].Split(" ")) | select -Unique) -Join " "
        }
        $array_out | select -Unique
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-08
      • 1970-01-01
      相关资源
      最近更新 更多