我有一些有很多行(数千行甚至更多)的数组。它有“列XXXXX”这样的列。
行示例:
Group_name = "proxy_users"
Column1 = "domain\Igor"
Column2 = null
.......
Column989 = 'domain\Andrew'
Column999 = 'domain\Mike'
创建新变量的正确和快速的方法是“ColumnXXX”忽略'null‘值的总和?
比如“域\igor,域\Andrew,域\mike”
我可以使用smth类似于$group的-Property选择-Property“列*”...but,如何求和,以及如何忽略null?
发布于 2018-02-18 12:54:25
可以使用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
的话。
发布于 2018-02-18 13:33:02
要用更简洁的Frode F.'s elegant ScriptProperty-based solution版本来补充PSv4+版本,这也是因为避免在属性定义脚本块中使用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的一个更快的替代方法。$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
结论:
Select-Object
-based解决方案(而不是向输入对象添加属性)比优化的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
https://stackoverflow.com/questions/48851718
复制相似问题