簡體   English   中英

powershell-在新的屬性中合並數組屬性

[英]powershell - combine array properties in new one

我有一些帶有很多行(數以千計)的數組。 它具有“列XXXXX ”列

行示例:

Group_name = "proxy_users"
Column1   = "domain\Igor"
Column2   = null
.......
Column989 = 'domain\Andrew'
Column999 = 'domain\Mike'

創建新變量(忽略“空”值將成為“ ColumnXXX”的總和)的正確和快速方法是什么?

就像“域\\ igor,域\\ Andrew,域\\ mike”

我可以像$ group一樣使用smth | 選擇-Property“ Column *” ...但是如何求和以及如何忽略null?

您可以使用ex列出所有屬性。 $_.psobject.properties ,過濾出所需的內容,然后使用-join組合值。 防爆

$o = [pscustomobject]@{
    Group_Name = "Test"
    Column1 = "Foo"
    Column2 = $null
    Column3 = "1"
}, [pscustomobject]@{
    Group_Name = "Test2"
    Column1 = $null
    Column2 = "Bar"
    Column3 = "2"
}

#Add property as constant
$o | ForEach-Object {
    $_ | Add-Member -NotePropertyName Summed -NotePropertyValue (($_.psobject.Properties | Where-Object { $_.Name -ne 'Group_name' -and $_.Value -ne 'null' } | Select-Object -ExpandProperty Value) -join '' )
}
$o | ft

或者您可以使用ScriptProperty來計算每次調用的值

#Remember to exclude itself to avoid infinite recursion
$o | Add-Member -MemberType ScriptProperty -Name Summed -Value {($this.psobject.Properties | Where-Object { $_.Name -ne 'Group_name' -and $_.Name -ne 'Summed' -and $_.Value -ne 'null' } | Select-Object -ExpandProperty Value) -join '' }
$o | ft

結果:

Group_Name Column1 Column2 Column3 Summed
---------- ------- ------- ------- ------
Test       Foo             1       Foo1
Test2              Bar     2       Bar2

或者,可以將$_.Name -like 'Column*' -and $_.Value -ne 'null' ColumnXXX $_.Name -like 'Column*' -and $_.Value -ne 'null' ColumnXXX $_.Name -like 'Column*' -and $_.Value -ne 'null'用作屬性過濾器(如果它們實際上被稱為ColumnXXX

用更簡潔的PSv4 +版本來補充Frode F.基於優雅的ScriptProperty的解決方案 ,該版本由於避免了在屬性定義腳本塊中使用cmdlet( 管道 ),從而使操作員 (具有大量的輸入對象,這可能很重要):

$o | Add-Member -PassThru -MemberType ScriptProperty -Name Joined -Value { 
 @($this.psobject.Properties.Where({$_.Name -match 'Column*'}).Value) -ne 'null' -join ', ' 
}

注意以下用途:

  • .Where()集合運算符(PSv4 +),是Where-Object cmdlet的更快替代方法。

  • 成員枚舉 (PSv3 +),在集合級別訪問屬性會生成元素的屬性值的數組
    例如, $this.psobject.Properties.Name產生$this.psobject.Properties集合的所有元素的.Name屬性值。

  • 將比較運算符-ne應用於數組值的 LHS,在這種情況下,該運算符充當過濾器 :將該運算符應用於每個元素 ,然后將匹配元素作為數組返回; 注意LHS周圍的@(...) ,即使將其僅返回單個值,也可確保將其視為數組。

使用問題中的樣本數據,以上結果(查找屬性Joined ):

Group_name : proxy_users
Column1    : domain\Igor
Column2    : null
Column989  : domain\Andrew
Column999  : domain\Mike
Joined     : domain\Igor, domain\Andrew, domain\Mike

通過上述優化,您甚至可以考慮使用一個更簡單的Select-Object解決方案,該解決方案構造包含輸入對象屬性( * )的自定義對象實例,以及包含感興趣的組合列值的新計算屬性:

$o | Select-Object *, @{ n='Joined'; e={ 
  @(($_.psobject.Properties.Where({$_.Name -match 'Column*'})).Value) -ne 'null' -join ', ' } 
}

此解決方案比上面的解決方案慢,但幅度不大。
需要注意的是,如果您將所有輸出收集在內存中,則新構造的對象除了原始對象外還會占用空間。


可選閱讀:性能比較; 管道使用的影響:

底部的代碼采用了Frode和我的回答的各種方法。

這是我機器上的一個示例計時-絕對數字並不重要,但是它們的比率是(盡管我不知道CPU核心數量和磁盤速度等因素會如何發揮作用)-輸入集大小為1000對象:

Approach                                 TotalSeconds
--------                                 ------------
add-member w/ scriptproperty - operators 0.35
select-object w/ noteproperty            0.40
add-member w/ scriptproperty - pipeline  0.72
add-member w/ noteproperty - pipeline    0.98

結論:

  • 在屬性定義中使用管道的解決方案的速度明顯慢了約2倍,即使輸入數量較大,該解決方案也似乎沒有變化。

  • 創建對象(而不是向輸入對象添加屬性)的基於優化Select-Object的解決方案僅比優化Add-Member解決方案稍慢。

測試的源代碼:

# The number of input objects to test with.
# Adjust to experiment.
$objCount = 1000

Write-Verbose -Verbose "# of input objects: $objCount"

$ndx = 0; $approaches = 'select-object w/ noteproperty', 
                        'add-member w/ scriptproperty - operators', 
                        'add-member w/ scriptproperty - pipeline', 
                        'add-member w/ noteproperty - pipeline'
$tempFile = New-TemporaryFile # requires PSv5+
$(foreach($approach in $approaches) {

  # Create test collection (recreate it in every iteration to support repeated Add-Member operations)
  $al = [System.Collections.ArrayList]::new()
  for ($i = 0; $i -lt $objCount; ++$i) {
    $null = $al.add([pscustomobject] @{ one = 1; Column1 = 'col1'; Column2 = 'col2'; Column3 = 'null'; Column4 = 'col4' })
  }

  Measure-Command {

    Write-Verbose -Verbose "Running: $approach..."
    switch ($ndx) {
      0 { # select-object w/ noteproperty
        $al | Select-Object *, @{ n='Joined'; e={ @(($_.psobject.Properties.Where({ $_.Name -match 'Column*'})).Value) -ne 'null' -join ', ' } } | 
          Export-Csv $tempFile  
        break
      }

      1 { # add-member w/ scriptproperty - operators
        $al | Add-Member -PassThru -MemberType ScriptProperty -Name Joined -Value { @($this.psobject.Properties.Where({ $_.Name -match 'Column*'}).Value) -ne 'null' -join ', ' } |
          Export-Csv $tempFile          
        break
      }

      2 { # add-member w/ scriptproperty - pipeline
        $al | Add-Member -PassThru -MemberType ScriptProperty -Name Joined -Value { ($this.psobject.Properties | Where-Object { $_.Name -match 'Column*'  -and $_.Value -ne 'null' } | Select-Object -ExpandProperty Value) -join ', ' }  | 
         Export-Csv $tempFile
         break
        }

        3 { # add-member w/ noteproperty - pipeline; requires an intermediate ForEach-Object call
          $al | ForEach-Object {
            $_ | Add-Member -PassThru -NotePropertyName Joined -NotePropertyValue (($_.psobject.Properties | Where-Object { $_.Name -match 'Column*' -and $_.Value -ne 'null' } | Select-Object -ExpandProperty Value) -join ', ' )
          } |
            Export-Csv $tempFile
        break
      }
      default { Throw "What are you doing here?" }
    }

    # Import-Csv $tempFile | Select-Object -First 1 Joined | Write-Verbose -Verbose

    ++$ndx

  } | Select-Object @{ n='Approach'; e={ $approach }}, @{ n='TotalSeconds'; e={ '{0:N2}' -f $_.TotalSeconds } }

}) | Sort-Object { [double] $_.TotalSeconds }

Remove-Item $tempFile

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM