如何动态地将 PSCustomObjects 添加到列表中
How to dynamically add PSCustomObjects to a list
我正在创建一个脚本来解析 CSV 文件,我将 CSV 中每个索引字段的内容作为 NoteProperty 存储在 PSCustomObject 中。
当我逐行解析文件时,我将 PSCustomObject 添加到列表类型中。当我输出我的列表时,我希望能够做类似的事情:
$list | Format-Table
并且可以很好地查看 csv 文件中的每一行,这些行被分成几列,标题在最上面。
问题
当我将 PSCustomObject 添加到列表时,它会将列表的类型更改为 PSCustomObject。实际上,这具有将对该 PSCustomObject 所做的任何更新追溯应用到列表中的每个元素的明显效果。
这是一个示例:
$list = [System.Collections.Generic.List[object]]::new()
$PSCustomObject = [PSCustomObject]@{ count = 0}
Foreach ($i in 1..5) {
$PSCustomObject.count +=1
$list.Add($PSCustomObject)
}
预期输出:
PS>$list
count
-----
1
2
3
4
5
实际输出:
PS>$list
count
-----
5
5
5
5
5
问题
有没有办法得到预期的输出?
限制/其他上下文(如果有帮助)
我正在尝试优化性能,因为我可能会解析非常大的 CSV 文件。这就是为什么我坚持使用列表。我知道列表中的 Add 方法比为每一行用 += 重新创建数组更快。我还使用运行空间池分别解析每个字段并通过 $list.$field[$lineNumber] = <field value>
更新 object,所以这就是为什么我需要一种方法来动态更新 PSCustomObject。我的代码的更大视图是:
$out = [hashtable]::Synchronized(@{})
$out.Add($key, @{'dataSets' = [List[object]]::new() } ) ### $key is the file name as I loop through each csv in a directory.
$rowTemplate = [PSCustomObject]@{rowNum = 0}
### Additional steps to prepare the $out dictionary and some other variables
...
...
try {
### Skip lines prior to the line with the headers
$fileParser = [System.IO.StreamReader]$path
Foreach ( $i in 1..$headerLineNumber ) {
[void]$fileParser.ReadLine()
}
### Load the file into a variable, and add empty PSCustomObjects for each line as a placeholder.
while ($null -ne ($line = $fileParser.ReadLine())) {
[void]$fileContents.Add($line)
$rowTemplate.RowNum += 1
[void]$out.$key.dataSets.Add($rowTemplate)
}
}
finally {$fileParser.close(); $fileParser.dispose()}
### Prepare the script block for each runspace
$runspaceScript = {
Param( $fileContents, $column, $columnIndex, $delimiter, $key, $out )
$columnValues = [System.Collections.ArrayList]::new()
$linecount = 0
Foreach ( $line in $fileContents) {
$entry = $line.split($delimiter)[$columnIndex]
$out.$key.dataSets[$linecount].$column = $entry
$linecount += 1
}
}
### Instantiate the runspace pool.
PS 版本 (5.1.19041)
您正在(重新)将相同的对象一遍又一遍地添加到列表中。
您需要在每次循环运行时创建一个新对象,但您仍然可以“模板化”对象 - 只需使用 hashtable/dictionary 而不是自定义对象:
# this hashtable will be our object "template"
$scaffold = @{ Count = 0}
foreach($i in 1..5){
$scaffold.Count += 1
$newObject = [pscustomobject]$scaffold
$list.Add($newObject)
}
作为 ,如果您正在为具有多个属性的对象创建模板,您可能需要考虑使用有序字典来保留属性的顺序:
# this hashtable will be our object "template"
$scaffold = [ordered]@{ ID = 0; Count = 0}
foreach($i in 1..5){
$scaffold['ID'] = Get-Random
$scaffold['Count'] = $i
$newObject = [pscustomobject]$scaffold
$list.Add($newObject)
}
我正在创建一个脚本来解析 CSV 文件,我将 CSV 中每个索引字段的内容作为 NoteProperty 存储在 PSCustomObject 中。
当我逐行解析文件时,我将 PSCustomObject 添加到列表类型中。当我输出我的列表时,我希望能够做类似的事情:
$list | Format-Table
并且可以很好地查看 csv 文件中的每一行,这些行被分成几列,标题在最上面。
问题
当我将 PSCustomObject 添加到列表时,它会将列表的类型更改为 PSCustomObject。实际上,这具有将对该 PSCustomObject 所做的任何更新追溯应用到列表中的每个元素的明显效果。
这是一个示例:
$list = [System.Collections.Generic.List[object]]::new()
$PSCustomObject = [PSCustomObject]@{ count = 0}
Foreach ($i in 1..5) {
$PSCustomObject.count +=1
$list.Add($PSCustomObject)
}
预期输出:
PS>$list
count
-----
1
2
3
4
5
实际输出:
PS>$list
count
-----
5
5
5
5
5
问题
有没有办法得到预期的输出?
限制/其他上下文(如果有帮助)
我正在尝试优化性能,因为我可能会解析非常大的 CSV 文件。这就是为什么我坚持使用列表。我知道列表中的 Add 方法比为每一行用 += 重新创建数组更快。我还使用运行空间池分别解析每个字段并通过 $list.$field[$lineNumber] = <field value>
更新 object,所以这就是为什么我需要一种方法来动态更新 PSCustomObject。我的代码的更大视图是:
$out = [hashtable]::Synchronized(@{})
$out.Add($key, @{'dataSets' = [List[object]]::new() } ) ### $key is the file name as I loop through each csv in a directory.
$rowTemplate = [PSCustomObject]@{rowNum = 0}
### Additional steps to prepare the $out dictionary and some other variables
...
...
try {
### Skip lines prior to the line with the headers
$fileParser = [System.IO.StreamReader]$path
Foreach ( $i in 1..$headerLineNumber ) {
[void]$fileParser.ReadLine()
}
### Load the file into a variable, and add empty PSCustomObjects for each line as a placeholder.
while ($null -ne ($line = $fileParser.ReadLine())) {
[void]$fileContents.Add($line)
$rowTemplate.RowNum += 1
[void]$out.$key.dataSets.Add($rowTemplate)
}
}
finally {$fileParser.close(); $fileParser.dispose()}
### Prepare the script block for each runspace
$runspaceScript = {
Param( $fileContents, $column, $columnIndex, $delimiter, $key, $out )
$columnValues = [System.Collections.ArrayList]::new()
$linecount = 0
Foreach ( $line in $fileContents) {
$entry = $line.split($delimiter)[$columnIndex]
$out.$key.dataSets[$linecount].$column = $entry
$linecount += 1
}
}
### Instantiate the runspace pool.
PS 版本 (5.1.19041)
您正在(重新)将相同的对象一遍又一遍地添加到列表中。
您需要在每次循环运行时创建一个新对象,但您仍然可以“模板化”对象 - 只需使用 hashtable/dictionary 而不是自定义对象:
# this hashtable will be our object "template"
$scaffold = @{ Count = 0}
foreach($i in 1..5){
$scaffold.Count += 1
$newObject = [pscustomobject]$scaffold
$list.Add($newObject)
}
作为
# this hashtable will be our object "template"
$scaffold = [ordered]@{ ID = 0; Count = 0}
foreach($i in 1..5){
$scaffold['ID'] = Get-Random
$scaffold['Count'] = $i
$newObject = [pscustomobject]$scaffold
$list.Add($newObject)
}