Why can't I store a hash table in an arraylist?

This is my code

$allTests = New-Object System.Collections.ArrayList
$singleTest = @{}

$singleTest.add("Type", "Human")

1..10 | foreach {

    $singleTest.add("Count", $_)
    $singleTest.add("Name", "FooBar...whatever..$_")
    $singleTest.add("Age", $_)
    $allTests.Add($singleTest) | out-null

    $singleTest.remove("Count")
    $singleTest.remove("Name")
    $singleTest.remove("Age")
}

      

From my understanding, my loop must add a copy of the hash table to the arraylist every time it receives

$allTests.Add($singleTest) | out-null

      

the loop continues, removes some of the keys, and this opens the way for the next iteration of the loop. This is not what is happening as the add command only adds a reference to the hash table.

If I check the final value

$allTests

      

it comes back

Name                           Value                                                                                                                   
----                           -----                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human                                                                                                                   
Type                           Human     

      

How do I fix this so that the actual copy of the hash table is stored in the array list?

I'm looking for a way out like

$allTests[0]

Name                           Value                                                                                                                   
----                           -----                                                                                                                   
Count                          1                                                                                                                       
Name                           FooBar...whatever..1                                                                                                    
Age                            1                                                                                                                       
Type                           Human  

$allTests[1]   

Name                           Value                                                                                                                   
----                           -----                                                                                                                   
Count                          2                                                                                                                       
Name                           FooBar...whatever..2                                                                                                    
Age                            2                                                                                                                       
Type                           Human  

      

+3


source to share


3 answers


Hashtables are references, when you create one object, all further operations against that hash table, including trying to get this information.

You can declare a new hash table for each loop to get around this.

$allTests = New-Object System.Collections.ArrayList

1..10 | foreach {
    $singleTest = @{}
    $singleTest.add("Type", "Human")
    $singleTest.add("Count", $_)
    $singleTest.add("Name", "FooBar...whatever..$_")
    $singleTest.add("Age", $_)
    $allTests.Add($singleTest) | Out-Null
}

      



or even that to cut out some bloat.

$allTests = New-Object System.Collections.ArrayList
1..10 | foreach {
    $allTests.Add(@{
        Type = "Human"
        Count = $_
        Name = "FooBar...Whatever..$_"
        Age = $_
    }) | Out-Null
}

      

Both of these answers will give you the expected result.

+4


source


Answer to

@ConnorLSW is a feature functional.

I have another solution for you that gives you more flexibility. I find myself creating custom objects that share some fields, so instead of creating new objects in each loop of the loop, you could define a base object outside of the loop just like you do now, and then inside the loop, you can change the value properties for that instance and then add it to your collection like this:



$allTests.Add($singleTest.Psobject.Copy())

      

This copies the content to a new object before pasting it. Now, you are not referring to the same object that you modify during the next iteration of the loop.

+1


source


Since hash tables are passed by reference, you simply add multiple references to the same hash table to your arraylist. You need to create a new copy of the hash table and then add it to the array list.

One option is to use a hash table .clone()

when you want to store a copy in the arraylist.

$allTests.Add($singleTest.clone()) | out-null

      

0


source







All Articles