0

Here is the code where i used array of hashtables

$podnumbers = @(1,3,1)

$podInfo = $null
$buffer = 0
$podarray = foreach ($pd in $podnumbers) {
    $podinfo = @()
    for($i=0;$i -lt $pd;$i = $i+1) {
    $pod = Read-Host -Prompt "Assign the pod numbers for",$esxarray[$buffer]
    Write-Output `n
    }
    @{$pd = $pod}
$buffer = $buffer + 1
}

Inputs I gave for $pod is 1 = 1 ; 3 = 2,4,6 ; 1 = 3

I want my arrays of hashtable to be like below,

Key : 1
Value : 1
Name : 1

Key : 3
Value : 2,4,6
Name : 3

Key : 1
Value : 3
Name : 1

But the actual output I got is,

Key : 1
Value : 1
Name : 1

Key : 3
Value : 2
Name : 3

Key : 3
Value : 4
Name : 3

Key : 3
Value : 6
Name : 3

Key : 1
Value : 3
Name : 1
3
  • 3
    You don't - either add/modify the existing key'd entry or find something other than a dictionary type to hold your data :) Commented Oct 29, 2020 at 12:30
  • Since you seem to configure ESX Pods, maybe edit the question and explain what you are trying to do. It's likely you need to invert the keys and values. Commented Oct 29, 2020 at 13:57
  • edited my objective Commented Oct 30, 2020 at 4:05

4 Answers 4

2

If you want to add multiple values to the same key, you need to test for whether the key is already present and act accordingly:

$keys = 1,2,3,1
$value = 'a value'
$hashtable = @{}

foreach($key in $keys){
  if(-not $hashtable.ContainsKey($key)){
    # First time we see this key, let's make sure the value is a resizable array
    $hashtable[$key] = @()
  }

  # Now we can safely add values regardless of whether the key already exists
  $hashtable[$key] += $value
}
Sign up to request clarification or add additional context in comments.

2 Comments

as per my requirement i wanna add key '1' twice or thrice with different values for each '1' key. eg: $hashtable = @{1 = 'host1' ; 2 = 'host2','host4'; 1 = 'host3'}
@DjangoUnchained yes? Nothing stops you from doing that using the above approach
1

To complement the answer from @Matthias:
You can't have duplicate keys in a hash table. This is by design. Hash tables contain a list of unique keys based on a binary search algorithm where each key is linked to a specific object (value).

There are two workarounds:

1. add an array of values to a specific hash table key:

$Keys = 1,2,2,3
$Values = 'a'..'d'
$HashTable = @{}
$i = 0
foreach($key in $Keys){ [array]$HashTable[$Key] += $Values[$i++] }

Iterating
The disadvantage is that you lose the order of the items (regardless if you use an ordered dictionary simply because some values share a single key).

Foreach ($Key in $Hashtable.Keys) {
    Foreach ($Value in @($Hashtable[$Key])) {
        Write-Host $Key '=' $Value
    }
}

3 = d
2 = b
2 = c
1 = a

Searching
The advantage is that the items are binary indexed and therefor quickly found.

$SearchKey = 2
Foreach ($Value in @($Hashtable[$SearchKey])) {
    Write-Host $SearchKey '=' $Value
}

2 = b
2 = c

2. or you might create a list (array) of hash tables (Key Value Pairs)

$Keys = 1,2,2,3
$Values = 'a'..'d'
$i = 0
$KeyValuePairs = foreach($key in $keys){ @{ $Key = $Values[$i++] } }

Iterating
The advantage is that the items will stay in order.
(Note that you have to invoke the GetEnumerator() method twice)

$KeyValuePairs.GetEnumerator().GetEnumerator() | Foreach-Object {
    Write-Host $_.Key '=' $_.Value
}

1 = a
2 = b
2 = c
3 = d

Searching
The disadvantage is that searching for the items is slower and little more comprehensive.

$SearchKey = 2
$KeyValuePairs.GetEnumerator().GetEnumerator() | 
    Where-Object Key -eq $SearchKey | Foreach-Object {
    Write-Host $_.Key '=' $_.Value
}

2 = b
2 = c

2 Comments

What if I want to add 3 values to key(3), that's how it should be. eg: for key 2 = 2 values will be added and for key 4 = 4 values will be added
That is already shown in the above answer. To make this more clear; I have updated it with different values (you might change this to 'a'..'z', if you want to play with more key-values). Anyways, if it still doesn't answer what you are looking for, I recommend you to (re)create the question with a minimal reproducible example (like the above examples) and an expected output (list of key-value pairs) as I either I still do not understand you, or you starting to contradict yourself.
0

I am doing this in a separate answer as your new redefined objective more specific than the initial question appeared. Instead, each response should be assigned to a the concerned podnumber.

Script:

$podnumbers = @(1,3,1)
$Inputs = 1,2,4,6,3
$c = 0
$podarray = foreach ($pd in $podnumbers) {
    $podinfo = @{}
    for($i=0; $i -lt $pd; $i = $i+1) {
        # $pod = Read-Host -Prompt "Assign the pod numbers for",$esxarray[$buffer]
        [array]$podinfo[$pd] += $Inputs[$c++]
    }
    $podinfo
}
$podarray

Output:

Name                           Value
----                           -----
1                              {1}
3                              {2, 4, 6}
1                              {3}

6 Comments

thank you iRon, i tried the above script but write-output of $podarray was empty in cli
I have tested again and for me, the above example works with both Windows PowerShell 5.1 and PowerShell Core 7
the $podinfo outside the inner for loop i.e } $podinfo } does it needed there?
Just $podinfo is similar to Write-Output $podinfo it writes the data to the pipeline, and eventually displays it. Meaning, you might leave it out (if you do not want to display the results) or consider to pass it on to another cmdlet (but that is a complete different question). Does it work now? Does it answer the question?
it neither threw error nor displayed the results for Write-Output $podarray
|
0

There's a simpler and faster way to do this: an array of hashtables. For this, I'll be using an 'ArrayList', which is a type of array that is not a fixed size.

ArrayLists keep PowerShell from having to recreate an array every time you want to add a new item, which is great for foreach operations.

I'm going to go ahead and just present a simple example instead of integrating it into your code. Given the age of this question, it's doubtful you still need it, so this is more for everyone else.

EXAMPLE CODE
# Make sure this is initialized outside BEFORE the foreach loop:
$arr = New-Object Collections.ArrayList
#OR
$arr = [Collections.ArrayList]::new()

# Normally the 'Add' method for ArrayList outputs the updated count,
# setting it to the $null variable prevents that.
$null = $arr.Add( @{foo='bar'} )
$null = $arr.Add( @{foo='test'} )

As for iterating over the resulting array, here are a few good ways of doing so:

PER-ITEM ITERATION
$arr.ForEach({$_.GetEnumerator()}).ForEach({
  "Key: " + $ht.Key; "Value: " + $ht.Value })

#OR

foreach ($ht in $arr) {
  "Key: " + $ht.Keys; "Value: " + $ht.Values }
output:
Key: foo
Value: bar
Key: foo
Value: test
PER-KEY ITERATION
foreach ($k in ($arr.Keys | Get-Unique)) {
  "Key: $k"; "Value(s): " + $arr.$k }
output:
Key: foo
Value(s): bar test

I'm deliberately avoiding using ForEach-Object in these examples due to its performance issues in every version of PowerShell (7.2.1 is the current version as of writing). You can read more about that here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.