3

我正在使用自定义对象来保存一组 SQL Server 对象的名称和架构。我将对象放入一个数组中,然后我得到另一组对象并将它们放入另一个数组中。我现在想做的是找到两个数组之间的所有完全匹配。

我目前正在使用这个:

$filteredSQLObjects = @()

foreach ($SQLObject1 in $SQLObjects1)
{
    foreach ($SQLObject2 in $SQLObjects2)
    {
        if ($SQLObject1.Name   -eq $SQLObject2.Name -and
            $SQLObject1.Schema -eq $SQLObject2.Schema)
        {
            $filteredSQLObjects += $SQLObject1
        }
    }
}

有没有更好/更快/更清洁的方法来做到这一点?最初,当我只是在处理字符串数组时,我可以遍历其中一个数组并在第二个数组中使用 -contains,但对象似乎不可能。

谢谢!

4

2 回答 2

4

我认为如果您在IsEqualTo自定义对象的方法中定义相等条件会更好。所以是这样的:

$myObject = New-Object PSObject
$myObject | Add-Member -MemberType NoteProperty -Name Name -Value $name
$myObject | Add-Member -MemberType NoteProperty -Name Schema -Value $schema
$myObject | Add-Member -MemberType ScriptMethod -Name IsEqualTo -Value {
    param (
        [PSObject]$Object
    )

    return (($this.Name -eq $Object.Name) -and ($this.Schema -eq $Object.Schema))
}

然后你可以像 Keith 向我们展示的那样做一个单行,或者只是做你的双重foreach迭代。无论您认为哪个更具可读性:

$filteredSQLObjects = $SQLObjects1 | Where-Object { $SQLObject1 = $_; $SQLObjects2 | Where-Object { $_.IsEqualTo($SQLOBject1) } }

foreach ($SQLObject1 in $SQLObjects1)
{
    foreach ($SQLObject2 in $SQLObjects2)
    {
        if ($SQLObject1.IsEqualTo($SQLObject2))
        {
            $filteredSQLObjects += $SQLObject1
        }
    }
}

编辑

好的,首先,您不能添加Equals成员,因为它已经存在于System.Object(doh!)。所以我想IsEqualTo将不得不这样做。

你可以做的是定义你自己的函数Intersect-Object(相当于.NET的Enumerable.Intersect方法),它接受管道输入并返回两个序列的集合交集(出现在两个序列中的那些)。请注意,我尚未完全实现此功能(假设集合中的每个项目由指定SequenceIsEqualTo方法,在添加等之前不检查重复项$filteredSequence),但我希望你明白这一点。

function Intersect-Object
{
    param (
        [Parameter(ValueFromPipeline = $true)]
        [PSObject]$Object,
        [Parameter(Mandatory = $true)]
        [PSObject[]]$Sequence
    )

    begin
    {
        $filteredSequence = @()
    }

    process
    {
        $Sequence | Where-Object { $_.IsEqualTo($Object) } | ForEach-Object { $filteredSequence += $_ }
    }

    end
    {
        return $filteredSequence
    }
}

然后你的双foreach循环变成这样:

$filteredSQLObjects = $SQLObjects1 | Intersect-Object -Sequence $SQLObjects2
于 2010-08-04T15:55:46.093 回答
2

如果你在控制台上写这个,你可以把它浓缩成一个合适的单行:

$filtered = $SQLObjects1 | ? {$o1=$_; $SQLObjects2 | ? {$_.Name -eq $o1.Schema `
                                                   -and $_.Name -eq $o1.Schema}}

但是在一个脚本中,我会像你拥有它一样扩展它。这种方式更具可读性。

于 2010-08-04T15:31:41.947 回答