Powershell: How to modify an array in the parent scope from within a function

תשובה Powershell: How to modify an array in the parent scope from within a function

  • Wednesday, January 09, 2013 6:19 PM
     
      Has Code

    I'm writing a function that creates an array, and inside a second function called from the first, I want to add values to the array. I found a way to make it work, but it seems "costly" since I believe it recreates the array from scratch every time I add to it. I read about a way to pass the array as a [ref], but it looks more complicated that I thought it should be. Is there a better way to do this, or is this the right way to do it and the additional overhead of recreating the array is so small I shouldn't worry about it?

    I guess I am really asking if there is a way to use the <variable> += <string> method of adding to the array, but have it act on the parent scope?

    Thanks for your input.

    TestFunctionScope.ps1:

    function Calling-Function
    {
    	Test-Function
    }
    
    function Test-Function
    {
    	$MyArray = ("aaa", "bbb", "ccc")
    	function AddToArray ($String1, $String2) {
    		set-variable MyArray ($MyArray + ($String1)) -scope 1
    		# 3 other attempts to add a string to the array -- None of these add the string to the parent scope's variable
    		$MyArray += $String2
    		$Script:MyArray += $String2
    		$Global:MyArray += $String2
    	}
    	AddToArray "ddd" "eee"
    	"Contents of Array after running AddToArray Function:"
    	$MyArray
    }

    Output:

    PS C:\~Working> . .\TestFunctionScope.ps1
    PS C:\~Working> Calling-Function
    Contents of Array after running AddToArray Function:
    aaa
    bbb
    ccc
    ddd
    PS C:\~Working>



    • Edited by Vizoere1 Wednesday, January 09, 2013 6:21 PM Added "Powershell" to title
    •  

All Replies

  • Wednesday, January 09, 2013 6:54 PM
    Moderator
     
      Has Code

    Hi,

    You can also use the [Ref] type accelerator; e.g.:


    function AppendTo-Array([Ref] $theArray, $newItem) {
      $theArray.Value += $newItem
    }
    
    $arr = "a","b","c"
    AppendTo-Array ([Ref] $arr) "d"
    $arr  # now contains "a","b","c","d"

    Bill

  • Wednesday, January 09, 2013 7:05 PM
    Moderator
     
     Answered Has Code

    Adding to an array always creates a new array, regardless of whether it's done from within a function or not.

    For a few elements the overhead is trivial.  If you have to do a lot of it, switch to an arraylist

    You have to use the .add() method on an arraylist instead of the += operator, but because it doesn't create a new object you don't have to scope it inside the function:

    $arraylist = new-object collections.arraylist
    function test {
       [void]$arraylist.add('one')
       [void]$arraylist.add('two')
       [void]$arraylist.add('three')
      }
    test
    $arraylist


    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "


  • Wednesday, January 09, 2013 7:10 PM
    Moderator
     
     

    Hi,

    mjolinor is correct about the overhead; I wasn't paying attention very well. I agree that the ArrayList object can be more efficient if you're appending very frequently. You can always test two versions (standard array, += operator) and the ArrayList object using Measure-Command to see which is more efficient.

    Bill

  • Wednesday, January 09, 2013 7:56 PM
     
     
    Thanks for the note about it always creating a new array. That answers my immediate question. However I'm sure to need large arrays in other scripts so the info about arraylist is appreciated as well!
  • Wednesday, January 09, 2013 7:57 PM
     
     
    I hadn't seen measure-command before. That's pretty awesome. Thanks Bill!