Powershell でオブジェクトの配列内で一致するものを見つける
-
25-09-2019 - |
質問
カスタム オブジェクトを使用して、一連の 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}}
あなたはそれを持っているように、しかし、スクリプトの中で、私はそれを拡大します。それはそのように読みやすくています。