Powershell - Как эффективно отфильтровать объект массива с помощью нескольких ключей / полей / столбцов другого объекта массива? - PullRequest
0 голосов
/ 30 марта 2019

Я пытаюсь получить элементы в объекте массива (имеет все данные и намного больше строк) (объект массива 1), который также существует в другом массиве (объект массива 2) (имеет некоторые поля и меньше строк )

Как бы я получил данные из объекта массива 1, используя несколько полей, так как много полей повторяются?

Важный момент: ни одна запись в поле не является уникальной, но комбинации из 4 полей имеют значение

В частности, как это сделать за несколько шагов / строк кода и без большого количества времени и / или потребления ресурсов (я могу понять, как это сделать, используя циклы, но это неэффективно)

Пример

ОБЪЕКТ Массива 1

Number : 10
Place  : UT
Color  : yellow
Zone   : FAHIVT
Group  : 20


Number : 29
Place  : NY
Color  : white
Zone   : HWOUKK
Group  : 8


Number : 66
Place  : TX
Color  : black
Zone   : KZZGKI
Group  : 2


number : 127
Place  : AL
Color  : white
Zone   : DMXDZR
Group  : 14

Массив объектов 2

Place : NY
Color : white
Group : 2
Zone  : TVQJPN

Place : PA
Color : blue
Group : 4
Zone  : AAYYSN

Place : NJ
Color : red
Group : 17
Zone  : DXKSVE

Результат, который я ищу после сопоставления или фильтрации, похож на

фильтрованный объект Array 1

number : 1730
Place  : NY
Color  : white
Zone   : TVQJPN
Group  : 2



number : 2199
Place  : PA
Color  : blue
Zone   : AAYYSN
Group  : 4



number : 2746
Place  : NJ
Color  : red
Zone   : DXKSVE
Group  : 17

Я закончил тем, что выполнил какую-то «Инженерную функцию» и соединил 4 поля, которые уникальны как комбо, в одну строку и добавил это как свойство к каждому из объектов Array. Combo = Place + Color + Zone + Group

Пример

number : 1730
Place  : NY
Color  : white
Zone   : TVQJPN
Group  : 2
Combo  : NYwhiteTVQJPN2

Предположим, $wholearray - это более крупный и полный массив, а $partialobject - тот, который нам нужно отфильтровать.

Вот мой ТЕКУЩИЙ КОД

    $wholearray.ForEach({
        $thisline = $_ ;
        $combo = $thisline.Place + $thisline.Color + $thisline.Zone + $thisline.Group;
        $wholearray.Where({$_ -eq $thisline}) | Add-Member -NotePropertyName Combo -NotePropertyValue $combo
    }

    $partialobject.ForEach({
        $thisline = $_ ;
        $combo = $thisline.Place + $thisline.Color + $thisline.Zone + $thisline.Group;
        $partialobject.Where({$_ -eq $thisline}) | Add-Member -NotePropertyName Combo -NotePropertyValue $combo
    }

    $filtereddata = $wholearray.Where({$_.Combo -in $($partialobject.Combo)}) 

Работает со средним временем обработки 0,08 сек на экземпляр в цикле Но это все еще медленно. Это займет 5 минут только для нескольких тысяч строк / экземпляров. Когда я должен сделать это с 20k или больше, это будет катастрофа. Все это можно сделать за 15 секунд, используя еще больше строк в Excel, используя vlookup. И POSH или CLI должны быть быстрее, чем Excel.

Как я могу сделать это более эффективным?

Как я могу сделать это быстрее?

Ответы [ 2 ]

1 голос
/ 30 марта 2019

Один Compare-Object может выполнить вашу задачу.

Поскольку Compare-Object не известен скоростью, у вас есть хотя бы альтернатива для измерения времени.

$Filtered = Compare-Object -Ref $WholeArray -Diff $PartialArray `
                           -Property Place,Color,Zone,Group `
                           -IncludeEqual -ExcludeDifferent -PassThru

Чтобы удалить вставленное свойство SideIndicator, вы можете сделать:

$Data = $Filtered | Select-Object -Property * -ExcludeProperty SideIndicator
1 голос
/ 30 марта 2019

Возможно, использование этого кода и таблицы поиска Hashtable ускорит процесс:

Добавьте свойство Combo к объектам $wholearray:

$wholearray | ForEach-Object {
    $combo = '{0}{1}{2}{3}' -f $_.Place, $_.Color, $_.Zone, $_.Group
    $_ | Add-Member -MemberType NoteProperty -Name Combo -Value $combo
}

Для объектов вЧастичный массив, вы создаете объект Hashtable:

$lookup = @{}

$partialarray | ForEach-Object {
    $combo = '{0}{1}{2}{3}' -f $_.Place, $_.Color, $_.Zone, $_.Group
    $lookup[$combo] = $true   # the key is the important thing here, the value doesn't matter
}

Затем получите ваши отфильтрованные данные, используя:

$filtereddata = $wholearray | Where-Object { $lookup.ContainsKey($_.Combo)} 

Надеюсь, что поможет

...