来自 powershell 阵列的独特组合 - 没有重复的组合

Unique Combos from powershell array - No duplicate combos

我正在尝试找出从 powershell 数组中获取独特组合的最佳方法。例如,我的数组可能是

@(B,C,D,E)

我希望得到这样的输出:

B
C
D
E
B,C
B,D
B,E
C,D
C,E
D,E
B,C,D
C,D,E
B,C,D,E

我不想重新安排组合。如果组合 C、D 已经存在,那么我不想要组合 D、C。这对我来说是多余的。

我查看了这里的函数:Get all combinations of an array

但它们不是我想要的。我一直在努力自己解决这个问题,但花了很多时间都没有成功。我想我会在这里问这个问题,这样如果其他人已经知道我不会在浪费时间。

谢谢!

我对此的疲惫尝试。我确实设法让它产生了预期的结果,但它是如何做到的并不那么优雅。使用递归功能。

Function Get-Permutations{
    Param(
        $theInput
    )
    $theInput | ForEach-Object{

        $element = $_
        $sansElement = ($theInput | Where-Object{$_ -ne $element})

        If($sansElement.Count -gt 1){
            # Build a collection of permutations using the remaining elements that were not isolated in this pass.
            # Use the single element since it is a valid permutation 
            $perms = ,$element
            For($elementIndex = 0;$elementIndex -le ($sansElement.Count - 1);$elementIndex++){
              $perms += ,@(,$element + $sansElement[0..$elementIndex] | sort-object)
            }

            # For loop does not send to output properly so that is the purpose of collecting the results of this pass in $perms
            $perms

            # If there are more than 2 elements in $sansElement then we need to be sure they are accounted for 
            If($sansElement -gt 2){Get-Permutations $sansElement}
        } 

    }
}

Get-Permutations B,C,D,E | %{$_ -join ","} | Sort-Object -Unique

我希望我能解释清楚自己....所以函数的每次传递都会接受一个数组。该数组的每个单独元素都将与由变量 $element$sansElement.

表示的数组的其余部分隔离

使用这些变量,我们构建了由这些元素组成的独立且逐渐变大的数组。让这个例子显示使用数组 1,2,3,4

1
1,2
1,2,3
1,2,3,4

以上每个"number"

2
2,1
2,1,3
2,1,3,4

等等。如果 returned 数组包含两个以上的元素(1,2 将与您示例中的 2,1 相同,因此我们不关心超过一个匹配项的对)我们将采用该数组和 运行 它通过相同的功能。

真正的问题是这里的逻辑(我知道这可能难以接受)创建了多个重复项。我想你可以创建一个哈希表,我将探索它,但它不会消除逻辑缺陷。

不管我如何自责,只要你没有成千上万的元素,这个过程仍然会产生结果。

Get-Permutations 会 return 和数组数组。 PowerShell 将每行显示一个元素。您要求以逗号分隔的输出,这是 -join 出现的地方。Sort-Object -Unique 接受那些排序的字符串并丢弃重复项。

示例输出

B
B,C
B,C,D
B,C,D,E
B,C,E      #< Missing from your example output.
B,D
B,D,E      #< Missing from your example output. 
B,E
C
C,D
C,D,E
C,E
D
E

这是对 C# 解决方案的改编 class 我认为它问了同样的问题。对于任何集合,找到所有子集,包括空集。

function Get-Subsets ($a){
    #uncomment following to ensure only unique inputs are parsed
    #e.g. 'B','C','D','E','E' would become 'B','C','D','E'
    #$a = $a | Select-Object -Unique
    #create an array to store output
    $l = @()
    #for any set of length n the maximum number of subsets is 2^n
    for ($i = 0; $i -lt [Math]::Pow(2,$a.Length); $i++)
    { 
        #temporary array to hold output
        [string[]]$out = New-Object string[] $a.length
        #iterate through each element
        for ($j = 0; $j -lt $a.Length; $j++)
        { 
            #start at the end of the array take elements, work your way towards the front
            if (($i -band (1 -shl ($a.Length - $j - 1))) -ne 0)
            {
                #store the subset in a temp array
                $out[$j] = $a[$j]
            }
        }
        #stick subset into an array
        $l += -join $out
    }
    #group the subsets by length, iterate through them and sort
    $l | Group-Object -Property Length | %{$_.Group | sort}
}

这样使用:

PS C:>Get-Subsets @('b','c','d','e')

b
c
d
e
bc
bd
be
cd
ce
de
bcd
bce
bde
cde
bcde

请注意,计算成本随输入数组的长度呈指数增长。

Elements     SecondstoComplete
15               46.3488228
14               13.4836299
13                3.6316713
12                1.2542701
11                0.4472637
10                0.1942997
 9                0.0867832