Arrays Powershell阵列:何时使用它们;何时避免它们;以及使用它们的问题
为什么.NET Framework ArrayList类.Add方法不能在PowerShell实现中工作 除非我被纠正,否则我认为我的故事的整体寓意可能是:不要假设本机PowerShell方法将与.NET方法相同,在PowerShell中尝试.NET方法时要小心 我寻求的最初解决方案是以数组的形式从函数返回日期列表,并将用户定义的日期范围作为参数。然后将引用日期数组来移动和读取以日期戳命名的文件 我遇到的第一个问题是创建动态数组。我不知道自己在做什么,并且在Arrays Powershell阵列:何时使用它们;何时避免它们;以及使用它们的问题,arrays,powershell,arraylist,generic-list,Arrays,Powershell,Arraylist,Generic List,为什么.NET Framework ArrayList类.Add方法不能在PowerShell实现中工作 除非我被纠正,否则我认为我的故事的整体寓意可能是:不要假设本机PowerShell方法将与.NET方法相同,在PowerShell中尝试.NET方法时要小心 我寻求的最初解决方案是以数组的形式从函数返回日期列表,并将用户定义的日期范围作为参数。然后将引用日期数组来移动和读取以日期戳命名的文件 我遇到的第一个问题是创建动态数组。我不知道自己在做什么,并且在@()数组声明上错误地调用了.NET.
@()
数组声明上错误地调用了.NET.Add
方法
使用“1”参数调用“Add”时出现异常:“集合大小固定。”
我认为我需要找到一个动态数组类型,而我真正的问题是我做得不对。这给了我一个不同的方向,直到很久以后,我才发现应该使用+=
语法将对象添加到PowerShell数组中
无论如何,在我回到如何正确使用PowerShell阵列之前,我已经开始了一些其他方面的工作
然后我找到了.NETArrayList
类。好的,很好。现在我有了一个动态数组对象。我阅读了文档,其中说我应该使用.Add
方法向集合中添加元素
然后,我开始寻求更深层次的理解,因为我经历了几天的沮丧,试图解决问题
我制作了一个一开始似乎可以工作的实现。它产生了一个日期范围,但也产生了一些奇怪的行为。我注意到返回了一些奇怪的日期,例如:
0001年1月1日星期一上午12:00:00
事实证明,我发现,这是当你这样做时得到的结果:
Get-Date 0
ArrayList
首先向数组元素返回索引值列表,然后返回数组值。那完全没有道理。我开始探索我是否正确地调用了函数,是否遇到了某种可变范围的问题,或者我只是疯了
我现在相当确信,我的挫败感是由于缺乏可靠的初学者参考资料造成的,该参考资料不仅展示了几个如何实现简单数组的示例,而且还描述了一些警告和替代解决方案
那么,让我在这里解释一下实现数组/集合的三种方法,以及我试图产生的解决方案,即一个日期范围内的日期列表
出于某种原因,我最初认为在Powershell中向.NET ArrayList添加元素的正确方法是使用.add方法。是的。我仍然不明白为什么这不起作用(说真的,有人请告诉我)。通过实验,我发现我可以通过使用+=
方法将对象添加到ArrayList中来获得准确的结果
不要这样做。这是绝对错误的。它将产生我上面描述的错误:
Function Get-DateRangeList {
[cmdletbinding()]
Param (
[datetime] $startDate,
[datetime] $endDate
)
$datesArray = [System.Collections.ArrayList]@() # Second method
for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) {
if ($d.DayOfWeek -ne 'Sunday') {
$datesArray.Add($d)
}
}
Return $datesArray
}
# Get one week of dates, ending with yesterday's date
$startDate = Get-Date
$endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range
$startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range
$datesList = Get-DateRangeList $startDate $endDate
# Loop through the dates
Foreach ($d in $datesList) {
# Do something with each date, e.g., format the date as part of a list
# of date-stamped files to retrieve
$d
}
下面有三个代码示例。在每个示例中,代码都是相同的。我所做的就是注释/取消注释相应的实例化行和方法行
首先,使用本机PowerShell阵列对象:
Function Get-DateRangeList {
[cmdletbinding()]
Param (
[datetime] $startDate,
[datetime] $endDate
)
$datesArray = @() # First method
#$datesArray = [System.Collections.ArrayList]@() # Second method
#$datesArray = New-Object System.Collections.Generic.List[System.Object] # Third method
for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) {
if ($d.DayOfWeek -ne 'Sunday') {
$datesArray += $d # First and second method: += is the method to add elements to: Powershell array; or .NET ArrayList (confusing)
#$datesArray.Add($d) # Third method: .Add is the method to add elements to: .NET Generic List
}
}
Return $datesArray
}
# Get one week of dates, ending with yesterday's date
$startDate = Get-Date
$endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range
$startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range
$datesList = Get-DateRangeList $startDate $endDate
# Loop through the dates
Foreach ($d in $datesList) {
# Do something with each date, e.g., format the date as part of a list
# of date-stamped files to retrieve
"FileName_{0}.txt" -f $d.ToString("yyyyMMdd")
}
第二,使用:
第三,使用:
所有这三项工作。为什么你更喜欢一个而不是另一个?本机PowerShell数组和.NET FrameworkArrayList
类都会生成非强类型的对象集合,因此您可以这样做(在PowerShell数组实现中):
Powershell阵列对于非常大的阵列来说效率不高。对于非常大的集合,ArrayList是一个更好的选择
对于同一类型的大型对象集合,.NETFramework通用列表似乎是最佳选择。在我的示例中,我想要一个日期列表。每个日期都是相同的数据类型,因此我不需要混合对象类型。因此,我正在部署的解决方案是上面的第三个工作示例
我很欣赏Dave Wyatt在2013 Powershell.org上发表的关于以下主题的文章:。特别是+=
方法,添加新元素,然后销毁旧数组。如果收集量很大,这将变得非常低效
我发布这些解决方案和讨论,希望其他初学者能更容易地找到我所寻求的答案
是的-没错-我不遵守某些人认为严格的PowerShell语法礼仪。我在函数中使用了return
语句,因此很明显函数产生了什么。我更喜欢那些看起来杂乱无章而不是紧凑的可读代码。这是我的偏好,我会坚持下去
有关日期列表的更像PowerShell的实现,我建议读者参考。大多数时候,我看到阵列添加时,完全没有必要。每当表达式返回多个对象时,Powershell管道都会自动为您创建数组,而且会非常高效 考虑:
Clear-Host
Function Get-DateRangeList {
[cmdletbinding()]
Param (
[datetime] $startDate,
[datetime] $endDate
)
$datesArray =
for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) {
if ($d.DayOfWeek -ne 'Sunday') {
$d
}
}
Return ,$datesArray
}
# Get one week of dates, ending with yesterday's date
$startDate = Get-Date
$endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range
$startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range
$datesList = Get-DateRangeList $startDate $endDate
# Loop through the dates
Foreach ($d in $datesList) {
# Do something with each date, e.g., format the date as part of a list of date-stamped files to retrieve
“FileName_{0}.txt" -f $d.ToString("yyyyMMdd")
}
只需创建和输出对象,并将结果赋回变量,就可以得到一个数组。关于OP:Collections的第3段。arraylist在powershell中工作,例如:
# Create arraylist with space for 20 object
$ar = new-object collections.arraylist 20
$ar.add("hello everybody")
$ar.add([datetime]::now)
$ar.add( (gps)[9])
$ar[0] # returns string
$ar[1] # returns datetime
$ar[2] # returns tenth process
$ar.count # returns 3
我认为这样做的好处是更仔细地阅读arraylist的MSDN文档
如果在PS中的arraylist上使用+=,它将从arraylist中获取元素和新元素,并创建一个数组。我相信这是一种试图保护用户不受您偶然发现的.NET复杂性的影响的尝试。(我怀疑PS产品团队的一个主要用例是一个不是fami的用户
$myArray = @(1, 2, 3, "A", "B", "C")
Clear-Host
Function Get-DateRangeList {
[cmdletbinding()]
Param (
[datetime] $startDate,
[datetime] $endDate
)
$datesArray =
for ($d = $startDate; $d -le $endDate; $d = $d.AddDays(1)) {
if ($d.DayOfWeek -ne 'Sunday') {
$d
}
}
Return ,$datesArray
}
# Get one week of dates, ending with yesterday's date
$startDate = Get-Date
$endDate = $startDate.AddDays(-1) # Get yesterday's date as last date in range
$startDate = $endDate.AddDays(-7) # Get 7th prior date as first date in range
$datesList = Get-DateRangeList $startDate $endDate
# Loop through the dates
Foreach ($d in $datesList) {
# Do something with each date, e.g., format the date as part of a list of date-stamped files to retrieve
“FileName_{0}.txt" -f $d.ToString("yyyyMMdd")
}
# Create arraylist with space for 20 object
$ar = new-object collections.arraylist 20
$ar.add("hello everybody")
$ar.add([datetime]::now)
$ar.add( (gps)[9])
$ar[0] # returns string
$ar[1] # returns datetime
$ar[2] # returns tenth process
$ar.count # returns 3
# Fails because PS unrolls the array and thinks that each element is a
# different argument to String..ctor
$stringFromCharArray = new-object string $charArray
# Wrap $charArray to get it to work
$stringFromCharArray = new-object string @(,$charArray)
# This also works
$stringFromCharArray = new-object string (,$charArray)