Home > Software engineering >  A dictionary inside of a dictionary in PowerShell
A dictionary inside of a dictionary in PowerShell

Time:02-10

So, I'm rather new to PowerShell and just can't figure out how to use the arrays/lists/hashtables. I basically want to do the following portrayed by Python:

entries = {
    'one' : {
        'id': '1',
        'text': 'ok'
    },
    'two' : {
        'id': '2',
        'text': 'no'
    }
}

for entry in entries:
    print(entries[entry]['id'])

Output:

1

2


But how does this work in PowerShell? I've tried the following:

$entries = @{
    one = @{
        id = "1";
        text = "ok"
    };
    two = @{
        id = "2";
        text = "no"
    }
}

And now I can't figure out how to access the information.

foreach ($entry in $entries) {
   Write-Host $entries[$entry]['id']
}

=> Error

CodePudding user response:

PowerShell prevents implicit iteration over dictionaries to avoid accidental "unrolling".

You can work around this and loop through the contained key-value pairs by calling GetEnumerator() explicitly:

foreach($kvp in $entries.GetEnumerator()){
    Write-Host $kvp.Value['id']
}

For something closer to the python example, you can also extract the key values and iterate over those:

foreach($key in $entries.get_Keys()){
    Write-Host $entries[$key]['id']
}

Note: You'll find that iterating over $entries.Keys works too, but I strongly recommend never using that, because PowerShell resolves dictionary keys via property access, so you'll get unexpected behavior if the dictionary contains an entry with the key "Keys":

$entries = @{
    Keys = 'a','b'
    a = 'discoverable'
    b = 'also discoverable'
    c = 'you will never find me'
}

foreach($key in $entries.Keys){ # suddenly resolves to just `'a', 'b'`
    Write-Host $entries[$key]
}

You'll see only the output:

discoverable
also discoverable

Not the Keys or c entries

CodePudding user response:

To complement Mathias R. Jessen's helpful answer with a more concise alternative that takes advantage of member enumeration:

# Implicitly loops over all entry values and from each 
# gets the 'Id' entry value from the nested hashtable. 
$entries.Values.Id  # -> 2, 1

Note: As with .Keys vs. .get_Keys(), you may choose to routinely use .get_Values() instead of .Values to avoid problems with keys literally named Values.

  • Related