Converting hashtable to array of strings

后端 未结 5 2059
一整个雨季
一整个雨季 2021-02-18 23:33

How can I convert a hashtable to an array of strings? Suppose $l_table is a hashtable. If I try

$l_array = $l_table | format-table

then $l_arra

5条回答
  •  我在风中等你
    2021-02-19 00:03

    While the original poster might have wanted an array of strings corresponding to the output of Format-Table, as the supplied attempts and poster's own answer/comments might suggest, the wording of the question heading is more typical of someone wishing to convert the hash table itself into an array of each item's value (converted to String if not already a String). For those looking for a solution to this problem I present the following (since there doesn't seem to be a similar question as yet):-

    The simplistic answer is to use

    [string[]]$l_table.values
    

    and this does give an array of strings as desired.

    Note: $l_table.values is a [System.Collections.Hashtable+ValueCollection] which is why the conversion to [string[]] is necessary even if the values are already strings. For example,

    'Found {0} with submatch {1}' -f [string[]]$matches.values
    

    won't work without it. (The other possible problem is mentioned next.)

    The major flaw with $l_table.values is that, unless the hash table was defined to be [ordered] (PSv3+), the order of the items is undefined (and can change as the hash table is modified). Often, when converting a hash table to an array, it is desired to have a certain ordering of the elements in that array. Indeed, sometimes the keys are (positive) integers and the intent is that the resultant array use the same values as array indexes (see $matches example above). To create this type of array, use

    [string[]]$l_table[($l_table.keys | sort)]
    

    or, if the values are already strings, just

    $l_table[($l_table.keys | sort)]
    

    to invoke Powershell's collection slicing functionality (whereby a single expression can produce an array of independently selected collection items by using an array expression as the index. E.g. $array[1,3,5,9], $array[1,2,3,4,5] or $array[1..5]). Note that this will only produce an array with the keys as the indexes if the keys form a contiguous range starting at 0. However, since the indexing expression is a pipeline, it is possible to get just about anything as the required array of keys. To get a resultant array from a 'sparse' hash table (of non-string values) use

    [string[]]$l_table[0..($l_table.keys | sort -descending)[0]]
    #
    # ($l_table.keys | sort -descending) produces a sorted array of key values
    # with the largest value in element 0
    #
    

    Now the resultant array will have the integer keys correctly corresponding to the appropriate index value by having any intervening (unused) array items set to "" (i.e. [string]$null). If this is a problem then a two step process can be used to leave the 'missing' entries as $null. Firstly, convert a non-string hash table to strings without adding entries by building a new hash table one dictionary pair at a time (using GetEnumerator()). Secondly, don't use [string[]] in order to leave $null in the 'unused' items when converting the (now string) hash table to an array as follows

    ($l_table.getenumerator() | foreach -begin {$str_table = @{}} -process {$str_table.add($_.key,[string]$_.value)} -end {$str_table[0..($str_table.keys | sort -descending)[0]]})
    

    or perhaps more efficiently (by removing the potentially costly sort)

    ($l_table.getenumerator() | foreach -begin {$maxkey = 0; $str_table = @{}} -process {$str_table.add($_.key,[string]$_.value); if ($maxkey -lt $_.key){$maxkey = $_.key}} -end {$str_table[0..$maxkey]})
    

    Note: for a sparse hash table of string values the initial form without conversion

    $l_table[0..($l_table.keys | sort -descending)[0]]
    

    will work but the use of [string[]] will change any missing entries from $null to "" if desired.

提交回复
热议问题