العثور على مباريات في صفائف الأشياء في PowerShell
-
25-09-2019 - |
سؤال
أنا أستخدم كائنات مخصصة للاحتفاظ بالاسم والمخطط من مجموعة من كائنات 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
}
}
}
هل هناك طريقة أفضل/أسرع/أنظف للقيام بذلك؟ في الأصل عندما كنت أعمل فقط مع صفائف من الأوتار ، يمكنني فقط أن أحلق من خلال إحدى المصفوفات واستخدامها في الثانية ، ولكن مع الأشياء التي لا تبدو ممكنة.
شكرًا!
المحلول
أعتقد أنه من الأفضل أن تحدد حالة المساواة في 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's 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
نصائح أخرى
يمكنك تكثيف هذا إلى خط واحد سيكون مناسبًا إذا كنت تكتب هذا في وحدة التحكم:
$filtered = $SQLObjects1 | ? {$o1=$_; $SQLObjects2 | ? {$_.Name -eq $o1.Schema `
-and $_.Name -eq $o1.Schema}}
لكن في البرنامج النصي ، أود توسيعه كما لديك. إنه أكثر قابلية للقراءة بهذه الطريقة.