質問

カスタム オブジェクトを使用して、一連の 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 を使用することができましたが、オブジェクトの場合はそれが不可能のようです。

ありがとう!

役に立ちましたか?

解決

等価条件を定義した方が良いと思います 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 (やった!)。だから私はそう思います IsEqualTo 代わりにやらなければなりません。

あなたができることは、という独自の関数を定義することです Intersect-Object (.NETのものと同等 Enumerable.Intersect メソッド) は、パイプライン入力を受け取り、2 つのシーケンス (両方のシーケンスに現れるもの) の集合集合を返します。この関数は完全には実装されていないことに注意してください (コレクション内の各項目が で指定されていると仮定しています) 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

他のヒント

あなたは、コンソールでこれを書いていた場合には適切であろうワンライナーにこれを凝縮できます:

$filtered = $SQLObjects1 | ? {$o1=$_; $SQLObjects2 | ? {$_.Name -eq $o1.Schema `
                                                   -and $_.Name -eq $o1.Schema}}
あなたはそれを持っているように、

しかし、スクリプトの中で、私はそれを拡大します。それはそのように読みやすくています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top