Вопрос

Я использую пользовательские объекты для удержания имени и схемы от набора объектов 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))
}

Тогда вы можете сделать один вкладыш, подобный Кит, показал нам, или просто сделаю свой двойной 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's'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