3

カスタム オブジェクトを使用して、一連の SQL Server オブジェクトから名前とスキーマを保持しています。オブジェクトを配列に入れてから、別のオブジェクトのセットを取得して、それらを別の配列に入れます。私が今やりたいことは、2 つの配列間で完全に一致するものをすべて見つけることです。

私は現在これを使用しています:

$filteredSQLObjects = @()

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

これを行うためのより良い/より速い/よりクリーンな方法はありますか? もともと、文字列の配列を扱っていたときは、配列の 1 つをループして、2 番目の配列で -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))
}

次に、キースが示したようなワンライナーを実行するか、ダブル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は代わりにやらなければならないだろうと思います。

できることは、パイプライン入力を受け入れ、2つのシーケンス(両方のシーケンスに現れるもの)の設定された共通部分を返す、Intersect-Object(。NETのメソッドと同等の)という独自の関数を定義することです。Enumerable.Intersectこの関数は完全には実装されていないことに注意してください(によって指定されたコレクション内の各アイテムにメソッドがあり、追加する前に重複をチェックしないことを前提としていSequenceますIsEqualTo$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 に答える