在两个PowerShell阵列中查找常见项

时间:2014-08-19 13:12:52

标签: arrays powershell

我知道已经有一些堆栈溢出问题,但我已经尝试了很多解决方案并且不断出现同样的错误。问题是:

我有2个数组(每个索引代表一个文件夹)

$originDirsArr = @(2, 257, 256, 3, 4, 10)
$tempDirArr = @(2, 257, 256, 3, 4)

我想再次比较$ arr2 $ arr1,如果$ arr1中有东西不在$ arr2中,则删除它。即,在这种情况下,$ arr2中的10个DNE,因此该文件夹应该被删除。

这就是我的尝试:

$c = Compare-Object -ReferenceObject ($originDirsArr) `
 -DifferenceObject ($tempDirArr) -Passthru
$c

另外:

while ($t -lt $originDirsArr.length){
$originDirsArr[$t]
    if ( $tempDirArr -notContain $originDirsArr[$t]){
        "$_ does not exist in original and needs to be deleted"
    }else{
        "$_ does still exist in the temp"
    }
    $t++
}

最后:

Compare-Object $originDirsArr $tempDirArr | ForEach-Object { $_.InputObject }

每次我都会遇到某种错误,无论是ReferenceObject还是DifferenceObject都是null。我知道它不是null因为我可以打印出内容,即使在那个例子中在t上编入索引,我仍然有内容。

先谢谢,非常感谢任何帮助!

3 个答案:

答案 0 :(得分:5)

我对compare-object也有点厌恶。由于这些是简单的数组,因此单个foreach循环和-notcontains将起到作用。

$originDirsArr = @(2, 257, 256, 3, 4, 10)
$tempDirArr = @(2, 257, 256, 3, 4)

foreach ($item in $originDirsArr) {
    if ($tempDirArr -notcontains $item) {
        Write-Output "Do something with $item";
    }
}

答案 1 :(得分:2)

使用HashSet generic collection。它需要.NET 3.5。它有一个IntersectWith方法,它会修改集合,使其仅包含两个集合中的项目(例如AND两个集合):

$originDirsSet = New-Object 'Collections.Generic.HashSet[int]' ,@(2, 257, 256, 3, 4, 10)
$tempDirSet = @(2, 257, 256, 3, 4)
$originDirsSet.IntersectWith( $tempDirSet )
# $originalDirsSet now contains 2, 257, 256, 3, 4

它有其他基于集合的方法:

  • ExceptWith:从当前HashSet<T>对象中删除指定集合中的所有元素。
  • SymmetricExceptWith:修改当前HashSet<T>对象,使其仅包含该对象或指定集合中存在的元素,但不包含两者(即,这类似于XOR集合)。
  • UnionWith:修改当前HashSet<T>对象以包含其自身,指定集合或两者中存在的所有元素(即,这类似于OR集合。)< / LI>

答案 2 :(得分:2)

这是一个1班轮来做这件事。它与接受的答案相同,因为它遍历一个数组,然后使用-contains将该项与另一个数组进行比较。这里的区别是我们使用where-object函数并返回结果集,而不是在for循环中使用if语句。还使用PowerShell的简写表示法来减少代码量(无论是好的还是“坏的”都是有争议的)。

#setting up
$originDirsArr = @(2, 257, 256, 3, 4, 10)
$tempDirArr = @(2, 257, 256, 229, 3, 4)

#get items in 1 array but not the other 
[int[]]$leftOnly = $originDirsArr | ?{$tempDirArr -notcontains $_}

#or an intersect operation
[int[]]$intersect = $originDirsArr | ?{$tempDirArr -contains $_}

#display results
"Left Only"; $leftOnly 
"Intersect"; $intersect 

或者,如果您经常这样做,为这种类型的操作提供方便的功能可能会有用:

set-alias ?@@ Apply-ArrayOperation #http://stackoverflow.com/a/29758367/361842
function Apply-ArrayOperation {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position=0)]
        [object[]]$Left
        ,
        [Parameter(Mandatory,ParameterSetName='exclude', Position=1)]
        [switch]$exclude
        ,
        [Parameter(Mandatory,ParameterSetName='intersect', Position=1)]
        [switch]$intersect
        ,
        [Parameter(Mandatory,ParameterSetName='outersect', Position=1)] #not sure what the correct term for this is
        [switch]$outersect
        ,
        [Parameter(Mandatory,ParameterSetName='union', Position=1)] #not sure what the correct term for this is
        [switch]$union
        ,
        [Parameter(Mandatory,ParameterSetName='unionAll', Position=1)] #not sure what the correct term for this is
        [switch]$unionAll
        ,
        [Parameter(Mandatory, Position=2)]
        [object[]]$Right
    )
    begin {
        #doing this way so we can use a switch staement below, whilst having [switch] syntax for the function's caller 
        [int]$action = 1*$exclude.IsPresent + 2*$intersect.IsPresent + 3*$outersect.IsPresent + 4*$union.IsPresent + 5*$unionAll.IsPresent
    }
    process {
        switch($action) {
            1 {$Left | ?{$Right -notcontains $_}} 
            2 {$Left | ?{$Right -contains $_} }
            3 {@($Left | ?{$Right -notcontains $_}) + @($Right | ?{$Left -notcontains $_})}       
            4 {@($Left) + @($Right) | select -Unique}       
            5 {@($Left) + @($Right)}       
        }
    }
}

$array1 = @(1,3,5,7,9)
$array2 = @(2,3,4,5,6,7)

"Array 1"; $array1
"Array 1"; $array2

"Array 1 Exclude Array 2";   ?@@ $array1 -exclude $array2 
"Array 1 Intersect Array 2"; ?@@ $array1 -intersect $array2
"Array 1 Outersect Array 2"; ?@@ $array1 -outersect $array2
"Array 1 Union Array 2";     ?@@ $array1 -union $array2
"Array 1 UnionAll Array 2";  ?@@ $array1 -unionall $array2