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

时间:2015-02-04 20:55:58

标签: arrays powershell unique

我正在尝试找出从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

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

谢谢!

2 个答案:

答案 0 :(得分:3)

这是对我所采用的C#类的解决方案的改编,它提出了同样的问题。对于任何集合,查找所有子集,包括空集。

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

答案 1 :(得分:2)

我厌倦了这一点。我确实设法让它产生预期的结果,但它是如何做到的并不那么优雅。使用递归功能。

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

以上是针对每个“数字”进行的

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

等等。如果返回的数组包含的元素多于两个(1,2与示例中的2,1相同,所以我们不关心超出一个匹配的对)我们将采用该数组并通过功能相同。

真正的问题是这里的逻辑(我知道这可能很难吞下)会产生几个副本。我想你可以创建一个哈希表,我将探索它,但它不会消除逻辑缺陷。

只要你没有成千上万的元素,无论我打败自己,这个过程都会产生结果。

Get-Permutations将返回数组数组。 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