EGr
EGr

Reputation: 2172

Convert Hashtable Values In-Place

I have a hashtable with values that are a mix of int and string (sometimes string array) objects. I want to convert them all to strings, but I don't know an easy way to do this without "rebuilding" the hashtable, converting each value to a string. Is there an easier, more efficient way to do this without looping through the values?

Here is a simple example. This is the hash that I would want to convert:

PS C:\Users\me> $test | Select -ExpandProperty Values | % { $_.GetType() }

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object
True     True     String                                   System.Object
True     True     String                                   System.Object
True     True     Int32                                    System.ValueType
True     True     Int32                                    System.ValueType
True     True     Int32                                    System.ValueType

To this:

PS C:\Users\gross> $new_test | Select -ExpandProperty Values | % { $_.GetType() }

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object
True     True     String                                   System.Object
True     True     String                                   System.Object
True     True     String                                   System.Object
True     True     String                                   System.Object
True     True     String                                   System.Object

Upvotes: 2

Views: 2004

Answers (2)

briantist
briantist

Reputation: 47792

I don't think there's a "more efficient" way of changing the values. You can set the values of each key to a value of a new type ($hash[$key] = $hash[$key].ToString()) but this is complicated if you're looping because you're changing the object being enumerated.

You can get around this in a hacky way by making sure you enumerate through a copy of the hashtable's keys, but then modify the hash with that:

$hash = @{
    a = '1'
    b = 2
    c = 3
    d = '4'
    e = 5
}

Write-Host "`nBefore:`n"

$hash.Values | ForEach-Object { $_.GetType() }

$keys = [Array]::CreateInstance([String], $hash.Keys.Count)
$hash.Keys.CopyTo($keys, 0) | Out-Null


$keys | ForEach-Object {
    $hash[$_] = $hash[$_].ToString()
}

Write-Host "`nAfter:`n"

$hash.Values | ForEach-Object { $_.GetType() }

But to be honest, I think it's easier to just make a new one:

$hash = @{
    a = '1'
    b = 2
    c = 3
    d = '4'
    e = 5
}

Write-Host "`nBefore (`$hash):`n"

$hash.Values | ForEach-Object { $_.GetType() }

$newhash = @{}
$hash.Keys | ForEach-Object { $newhash[$_] = $hash[$_].ToString() }

Write-Host "`nAfter (`$newhash):`n"

$newhash.Values | ForEach-Object { $_.GetType() }

Upvotes: 1

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200273

Casting them to strings should suffice:

$($new_test.Keys) | % { $new_test[$key] = [string]$new_test[$key] }

or (if you don't want to cast all values indiscriminately):

($new_test.Keys | ? { $new_test[$_] -is [int] }) |
  % { $new_test[$key] = [string]$new_test[$key] }

Upvotes: 1

Related Questions