当前位置:  开发笔记 > 编程语言 > 正文

Powershell数组:何时使用它们; 何时避免; 和使用它们的问题

如何解决《Powershell数组:何时使用它们;何时避免;和使用它们的问题》经验,为你挑选了1个好方法。

为什么.NET Framework ArrayList类.Add方法在PowerShell实现中不起作用?

除非我另外纠正,否则我认为我的故事的整体道德可能是:不要假设本机PowerShell方法将与.NET方法相同,并且在PowerShell中尝试.NET方法时要小心.

我正在寻找的原始解决方案是从一个函数返回一个日期列表,作为一个数组,用户定义的日期范围作为参数.然后引用日期数组来移动和读取以日期戳命名的文件.

我遇到的第一个问题是创建一个动态数组.我不知道我在做什么,并且错误地.Add@()数组声明上调用.NET 方法.

使用"1"参数调用"Add"的异常:"Collection具有固定大小."

我认为我需要找到一个动态数组类型,当我真正的问题是我做得不对时.这让我走向了一个不同的方向,直到很久以后,我发现应该使用+=语法将对象添加到PowerShell数组中.

无论如何,在我回到如何正确使用PowerShell数组之前,我在其他一些切线上了.

然后我找到了.NET ArrayList类.好的.现在我有一个动态数组对象.我阅读了文档,其中说我应该使用该.Add方法向集合中添加元素.

然后开始寻求更深入的理解,因为我经历了几天头脑紧张的挫折试图解决问题.

我制作了一个最初工作的实现.它产生了一个日期范围 - 但它也产生了一些奇怪的行为.我观察到奇怪的日期返回,例如:

0001年1月1日星期一12:00:00 AM

事实证明,我发现这是你执行此操作时获得的结果:

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
}

现在,下面有三个代码示例,DO WORK.在每个示例中,代码都是相同的.我所做的就是对相应的实例化行和方法行进行注释/取消注释.

首先,使用本机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")
}

其次,使用.NET FrameworkArrayList:

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")
}

第三,使用.NET Framework通用列表:

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 Framework ArrayList类都生成非强类型对象的集合,因此您可以执行此操作(在Powershell数组实现中):

$myArray = @(1, 2, 3, "A", "B", "C")

对于非常大的阵列,Powershell阵列效率不高.对于非常大的集合,ArrayList是更好的选择.

对于非常大的同类型对象集合,.NET Framework通用列表似乎是最佳选择.在我的例子中,我想要一个日期列表.每个日期都是相同的数据类型,因此我不需要混合对象类型.因此,我正在部署的解决方案是上面的第三个工作示例.

我很欣赏Dave Wyatt 2013年关于该主题的Powershell.org文章:PowerShell性能:+ =运算符(以及何时避免它).特别是,该+=方法在循环内的每个传递中创建一个新的数组对象,添加新元素,然后销毁旧数组.对于大型集合,这变得非常低效.

我发布这些解决方案和讨论,希望其他初学者能更容易找到我想要的答案.

是的 - 这是对的 - 我不坚持某些人的想法是严格的PowerShell语法礼仪.我return在函数中使用了该语句,因此很明显函数产生了什么.我更喜欢可读代码,这些代码可能看起来庞大而不是紧张.这是我的偏好,我坚持认为.

对于更多PowerShell式的日期列表实现,我向读者推荐The Surly Admin发布的整洁实现.



1> mjolinor..:

大多数时候我看到阵列添加,这是完全没必要的.每当表达式返回多个对象时,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")
}

所需要的只是创建和输出您的对象,并将结果分配回您的变量,您将拥有一个数组.

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有