Get-ElementCombination.ps1

<#PSScriptInfo
  
.DESCRIPTION Finds combinations of elements
.VERSION 1.0.1
.GUID 4d2c4fef-77ed-453e-ab19-f0b5d411ab38
.AUTHOR Lee Holmes
  
#>


<#
 
.SYNOPSIS
Finds combinations of elements
 
.EXAMPLE
PS > Get-ElementCombination -Base 2 -MaxLength 3 | Foreach-Object { $_ -join "," }
 
0,0,0
0,0,1
0,1,0
0,1,1
1,0,0
1,0,1
1,1,0
1,1,1
 
PS > $chars = 'a','b','c'
PS > Get-ElementCombination -Base 3 -MaxLength 2 | % { -join ($_ | % { $chars[$_] }) }
 
aa
ab
ac
ba
bb
bc
ca
cb
cc
 
#>


#>
param(
    ## The number of elements in the set.
    [Parameter(Mandatory)]
    [ValidateRange(2, [UInt32]::MaxValue)]
    [UInt32] $Base,
    
    ## How long can the sequences be?
    [Parameter(Mandatory)]
    [ValidateRange(1, [UInt32]::MaxValue)]
    [UInt32] $MaxLength
)

## Hold the sequence
$currentValue = New-Object Int[] $MaxLength
$currentLength = 1

,$currentValue.Clone()

while ($true)
{
    $currentIndex = $maxLength - 1

    while ($true)
    {
        ## Increment the final element. If we haven't overflowed the
        ## base, then we're done
        $currentValue[$currentIndex]++;
        if ($currentValue[$currentIndex] -lt $Base)
        {
            break;
        }

        ## If we did overflow the base, then set this element back to
        ## zero and start working on the element to the left.
        $currentValue[$currentIndex] = 0;
        $currentIndex--;

        ## If we've gone past our max length, exit.
        if($currentIndex -lt 0)
        {
            return
        }

        ## If we've added a new element (i.e.: gone further to the left
        ## than we have before), we now have a new current length.
        if($currentLength -lt ($maxLength - $currentIndex))
        {
            $currentLength = $maxLength - $currentIndex
        }
    }

    ## Output the current combination
    ,$currentValue.Clone()
}