سؤال

أنا أستخدم كائنات مخصصة للاحتفاظ بالاسم والمخطط من مجموعة من كائنات 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}}

لكن في البرنامج النصي ، أود توسيعه كما لديك. إنه أكثر قابلية للقراءة بهذه الطريقة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top