数据行到字符串到数组问题
Data Rows to String to Array issue
我遇到了一个非常奇怪的问题。我有一个填充了一堆行的对象。我可以很好地访问它们,但我需要附加一个“。” (点)到其中的每个值,所以我最终使用 for each 循环将每条记录转换为字符串并添加一个“。”修剪值后。然而,现在的问题是,我想将这些行中的每一行(并且这些行只有一个 column/Item)分配给另一个 array/object,以便我以后可以访问它们。
问题是,即使我声明了一个 object/array 变量并分配字符串转换后的数据行,对象变量仍然被转换为字符串,我似乎无法避免它。
请帮忙。这是修改后的代码示例:
[String] $DBNms = @();
ForEach($DBName in $objDBNms){
$tempText += $DBName.Item(0).ToString().Trim() + "."
$DBNms += $tempText
}
Write-Host($DBNms.GetType()) #And this is showing up a string, while I want it to be an array.
如果我打印 $DBNms,它确实会显示一个字符串连接在一起成为一个字符串,而我实际上希望它像 $DBNms[0] = 第一个项目值,$DBNms[1] = 第二个物品价值等等。
[String] $DBNms = @();
makes $DBNms
a type-constrained variable, due to type literal [string]
being placed to the left of variable $DBNms
, whose type is then locked in as a string; that is, as a single string.
You were looking to create a string array, which in PowerShell is represented as [string[]]
:
[string[]] $DBNames = @()
PowerShell's type conversions are automatic (and very flexible), so that [String] $DBNms = @()
doesn't report an error, it quietly converts the empty array (@()
) to the empty string (as required by the type constraint):
PS> [string] $DBNames = @(); '' -eq $DBNames
True
A much more efficient way to collect values from multiple iterations in an array is to use the foreach
statement as an expression, which case PowerShell collects the outputs automatically for you:
[string[]] $DBNms = foreach ($DBName in $objDBNms){
# Output this expression's value as-is.
# PowerShell will collect the individual iterations' values for you.
$DBName.Item(0).ToString().Trim() + "."
}
The above is not only more concise than your original approach, it is more importantly more efficient:
In reality you cannot directly add (append to) an array, because it is an immutable data structure.
What PowerShell has to do whenever you use +=
with an array is to allocate a new array behind the scenes, with the original elements copied over and the new element(s) appended; the new array is then automatically assigned back to the variable.
Note: The alternative and next best solution to using the whole loop as an expression is to use an efficiently extensible list type, notably [System.Collections.Generic.List[object]]
(System.Collections.Generic.List`1
):
# Create the list.
# The 'System.' namespace prefix is optional.
[Collections.Generic.List[string]] $DBNms = @()
foreach ($DBName in $objDBNms) {
# Add to the list, using its .Add() method.
# Note: Do NOT try to add with +=
$DBNms.Add($DBName.Item(0).ToString().Trim() + ".")
}
You'll need this approach if your loop does more than outputting a single value per iteration, such as needing to append to multiple collections.
Note: It used to be common to use System.Collections.ArrayList
instances instead; however:
Use of this type is no longer recommended (see the warning in the linked help topic); use [System.Collections.Generic.List[object]]
instead, which additionally allows you to strongly type the collection (replace [object]
with the type of interest, such as [string]
in the code above).
It has the drawback of its .Add()
method having a return value, which you need to silence explicitly (e.g., $null = $lst.Add(...)
), so that it doesn't accidentally pollute your code's output stream (produce unexpected extra output).
我遇到了一个非常奇怪的问题。我有一个填充了一堆行的对象。我可以很好地访问它们,但我需要附加一个“。” (点)到其中的每个值,所以我最终使用 for each 循环将每条记录转换为字符串并添加一个“。”修剪值后。然而,现在的问题是,我想将这些行中的每一行(并且这些行只有一个 column/Item)分配给另一个 array/object,以便我以后可以访问它们。
问题是,即使我声明了一个 object/array 变量并分配字符串转换后的数据行,对象变量仍然被转换为字符串,我似乎无法避免它。
请帮忙。这是修改后的代码示例:
[String] $DBNms = @();
ForEach($DBName in $objDBNms){
$tempText += $DBName.Item(0).ToString().Trim() + "."
$DBNms += $tempText
}
Write-Host($DBNms.GetType()) #And this is showing up a string, while I want it to be an array.
如果我打印 $DBNms,它确实会显示一个字符串连接在一起成为一个字符串,而我实际上希望它像 $DBNms[0] = 第一个项目值,$DBNms[1] = 第二个物品价值等等。
[String] $DBNms = @();
makes $DBNms
a type-constrained variable, due to type literal [string]
being placed to the left of variable $DBNms
, whose type is then locked in as a string; that is, as a single string.
You were looking to create a string array, which in PowerShell is represented as [string[]]
:
[string[]] $DBNames = @()
PowerShell's type conversions are automatic (and very flexible), so that [String] $DBNms = @()
doesn't report an error, it quietly converts the empty array (@()
) to the empty string (as required by the type constraint):
PS> [string] $DBNames = @(); '' -eq $DBNames
True
A much more efficient way to collect values from multiple iterations in an array is to use the foreach
statement as an expression, which case PowerShell collects the outputs automatically for you:
[string[]] $DBNms = foreach ($DBName in $objDBNms){
# Output this expression's value as-is.
# PowerShell will collect the individual iterations' values for you.
$DBName.Item(0).ToString().Trim() + "."
}
The above is not only more concise than your original approach, it is more importantly more efficient:
In reality you cannot directly add (append to) an array, because it is an immutable data structure.
What PowerShell has to do whenever you use
+=
with an array is to allocate a new array behind the scenes, with the original elements copied over and the new element(s) appended; the new array is then automatically assigned back to the variable.
Note: The alternative and next best solution to using the whole loop as an expression is to use an efficiently extensible list type, notably [System.Collections.Generic.List[object]]
(System.Collections.Generic.List`1
):
# Create the list.
# The 'System.' namespace prefix is optional.
[Collections.Generic.List[string]] $DBNms = @()
foreach ($DBName in $objDBNms) {
# Add to the list, using its .Add() method.
# Note: Do NOT try to add with +=
$DBNms.Add($DBName.Item(0).ToString().Trim() + ".")
}
You'll need this approach if your loop does more than outputting a single value per iteration, such as needing to append to multiple collections.
Note: It used to be common to use instances instead; however:System.Collections.ArrayList
Use of this type is no longer recommended (see the warning in the linked help topic); use
[System.Collections.Generic.List[object]]
instead, which additionally allows you to strongly type the collection (replace[object]
with the type of interest, such as[string]
in the code above).It has the drawback of its
.Add()
method having a return value, which you need to silence explicitly (e.g.,$null = $lst.Add(...)
), so that it doesn't accidentally pollute your code's output stream (produce unexpected extra output).