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
source to share
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.
source to share
@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.
source to share
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
source to share