【问题标题】:Errors when returning values to the array将值返回到数组时出错
【发布时间】:2016-06-08 16:33:42
【问题描述】:

我尝试创建一个简单的优化脚本。这是我的代码:

# Analysis gives the initial inputs and outputs
$initialinputs  
$initialoutputs 

# The objective function
$F = ([math]::pow($initialinputs, 2)) * 2 - 3* $initialinputs
# Differentiation of the objective function
$DF = 2 * $initialinputs - 3
$ScaleFactor = 0.2

# If the optimum solution has been obtained, two termination measurements:
# maximum iteration and termination criterion(gradient)
$Maxloop = 100
$Termi = 0.001

# Create arrays
$InputsArr = @() #The array of inputs
$FunctionArr = @() #The array of function values
$DFunctionArr = @() # The array of differentiation values (Gradient)

# Calculations
#$InputsArr[0] = $initialinputs  #The first input
#$FunctionArr[0] = $F[$InputsArr[0]]
#$DFunctionArr[0] = $DF[$inputsArr[0]]

for ($Innerloop = 1; $Innerloop -le $Maxloop; $Innerloop++)
{
     # Calculate the second input
     $InputsArr[$innerloop] = $InputsArr[$Innerloop - 1] - $ScaleFactor * (2 * $InputsArr[$Innerloop - 1] - 3)

     $initialinputs = $InputsArr[$Innerloop]

     # Calculate the function value
     $FunctionArr[$innerloop] = ([math]::pow($initialinputs, 2)) * 2 - 3 * $initialinputs
     Return, $FunctionArr

     # Calculate the gradient value
     $DFunctionArr[$innerloop] = 2 * $initialinputs - 3
     return, $DFunctionArr

     # If the gradient value less than the termination criterion (gradient),
     # break the loop
     if ($DFunctionArr[$innerloop] -le $Termi)
     {
         break
     }
}

我创建了空数组,然后使用for 循环进行优化并将输出存储在数组中。但是我得到了一些错误,如下所示:

错误:+ $InputsArr[$Innerloop] = $initialinputs
错误:+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
错误:+ CategoryInfo:OperationStopped: (:) [], IndexOutOfRangeException
错误:+ FullyQualifiedErrorId:System.IndexOutOfRangeException

错误:+ $FunctionArr[$innerloop] = $Functionoutput
错误:+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
错误:+ CategoryInfo:OperationStopped: (:) [], IndexOutOfRangeException
错误:+ FullyQualifiedErrorId:System.IndexOutOfRangeException

我不太确定如何修复这些错误。如何将值返回到数组? += 是唯一的方法吗?我现在对数组感到困惑。

【问题讨论】:

    标签: arrays powershell


    【解决方案1】:

    当您像这样初始化一个数组时:$InputsArr = @(),powershell 会创建一个长度为 0 的数组。因此,当您尝试使用 $InputsArr[$innerloop] 对该数组进行寻址时,它会抛出一个错误,即元素 $innerloop 不存在。

    两种解决方案。您可以显式初始化特定类型和长度的数组:

    $InputsArr = New-Object double[] $MaxLoop

    或者,您可以在代码中使用 += 运算符向数组添加新值:

    $InputsArr += $InputsArr[$Innerloop - 1] - $ScaleFactor * (2 * $InputsArr[$Innerloop - 1] - 3) #Calculate the second input

    += 创建一个长度为 n+1 的新数组,复制旧数组,然后添加新值,因此对于大型数组来说效率非常低。见here

    【讨论】:

      【解决方案2】:

      @() 定义的 PowerShell 数组是动态调整大小的。除非它们实际上包含元素,否则您不能对其中的内容进行索引访问。这就是为什么在 for 循环中使用 $array[$index] 时会出现“索引越界”异常的原因。该数组还没有 $index 字段。

      基本上有两种填充PowerShell数组的方法:

      • 在循环中追加到现有数组:

        $array = @()
        for (...) {
          $array += $foo
        }
        
      • 回显循环内的元素并将循环输出分配给一个变量:

        $array = for (...) {
          $foo
        }
        

      对于较大数量的数组元素,应避免使用前者,因为每个追加操作 (+=) 都会创建一个大小增加的新数组,复制元素,然后将新数组分配给变量。后一种方法在性能方面要优越得多。后一种方法的唯一缺点是结果不会是数组,除非循环产生至少两个元素。您可以通过强制执行数组输出来缓解这种情况:@(for (...) {...})

      PowerShell 还允许您创建固定大小的数组:

      $size  = 100
      $array = New-Object Object[] $size
      

      但是,这样做通常没有任何好处。

      还要注意,循环中的第一条指令假定数组已经包含一个初始值:

      $InputsArr[$innerloop] = $InputsArr[$Innerloop - 1] - $ScaleFactor * (2 * $InputsArr[$Innerloop - 1] - 3) #Calculate the second input
      

      因此您需要在开始循环之前用一个元素预填充数组:

      $InputsArr = @($initialValue)
      

      话虽如此,还有更多 PoSh 方法可以用值填充数组,例如像这样:

      $i = $initialValue
      $array = @($i)
      $array += 1..$Maxloop | ForEach-Object {
        $i -= $ScaleFactor * (2 * $i - 3)
        $i
      }
      

      如果你想在同一个循环中填充多个数组(因为由于某种原因你不能为每个数组使用一个循环)追加可能是你最好的选择。像这样:

      $InputsArr    = @($initialinputs)
      $FunctionArr  = @($initialinputs)
      $DFunctionArr = @($initialinputs)
      for ($i = 1; $i -le $Maxloop -and $DFunctionsArr[-1] -le $Termi; $i++) {
          $InputsArr    += $InputsArr[-1] - $ScaleFactor * (2 * $InputsArr[-1] - 3)
          $FunctionArr  += ([Math]::Pow($InputsArr[-1], 2)) * 2 - 3 * $InputsArr[-1]
          $DFunctionArr += 2 * $InputsArr[-1] - 3
      }
      

      或者像这样,如果你以后不需要$InputsArr

      $FunctionArr  = @($initialinputs)
      $DFunctionArr = @($initialinputs)
      $v = $initialinputs
      for ($i = 1; $i -le $Maxloop -and $DFunctionsArr[-1] -le $Termi; $i++) {
          $v -= $ScaleFactor * (2 * $v - 3)
      
          $FunctionArr  += [Math]::Pow($v, 2) * 2 - 3 * $v
          $DFunctionArr += 2 * $v - 3
      }
      

      【讨论】:

      • 你说的最后一种方法只能将值存储在一个数组中。我想运行三个计算并分别存储这些值。 $InputsArr, $FunctionArr and $DfunctionArr这三个数组需要从$initialinputs = $InputsArr[$Innerloop]$FunctionArr[$innerloop] = ([math]::pow($initialinputs, 2)) * 2 - 3 * $initialinputs$DFunctionArr[$innerloop] = 2 * $initialinputs - 3获取不同的值。是否可以使用最后一种方法来实现?
      • 如果你想在同一个循环中填充多个数组,则在循环中附加到现有数组,显然。
      猜你喜欢
      • 2022-11-11
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 2019-03-18
      • 2021-09-16
      • 1970-01-01
      • 1970-01-01
      • 2016-02-22
      相关资源
      最近更新 更多