将哈希表转换为字符串数组

时间:2014-01-28 18:11:38

标签: powershell

如何将哈希表转换为字符串数组? 假设$ l_table是一个哈希表。如果我试试

$l_array = $l_table | format-table

然后$ l_array是一个数组,但是是一个“FormatEntryData”对象的数组。 如果我做

[string[]]$l_array = $l_table | format-table

然后$ l_array是一个字符串数组,但字符串都是“Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData”。如果我试试

$l_array = $l_table | out-string

然后$ l_array是一个单独的字符串。我已经尝试了很多其他的东西,但没有任何效果,没有手动循环,我真的不想这样做。

5 个答案:

答案 0 :(得分:16)

David I. McIntosh's own answer效果很好,但应该注意的是,结果数组的元素对应于默认输出的所有行,其中包括:

  • 空的前导和尾随行
  • 两个标题行(具有列名和分隔线的行)

Out-String只是将您在控制台(终端)中通常看到的内容发送到字符串,默认情况下发送为单个字符串,并将-Stream作为< em> array of strings。

以下是David的命令的变体,它删除了标题和空行:

[string[]] $l_array = ($l_table | out-string -stream) -notmatch '^$' | select -Skip 2

本答案的其余部分显示了如何控制获得的字符串表示;它使用PS v3 +语法简洁。

注意:为清楚起见,以下示例中的示例输入哈希表称为$ht(不是$l_table)。

  • 将所有作为字符串数组:

    $ht.Keys | % ToString
    
  • 将所有作为字符串数组:

    $ht.Values | % ToString
    
  • <key>=<value>格式获取键值对的自定义表示形式;请注意,需要.GetEnumerator()才能通过管道单独发送键值对 ;默认情况下,PowerShell将哈希表作为一个整体传递

    $ht.GetEnumerator()  | % { "$($_.Name)=$($_.Value)" }
    

请注意,虽然.ToString()(在插值期间也是隐式)适用于内置 .NET类型,但其他类型只会通常打印他们的完整类型名称,除非他们的.ToString()方法被覆盖以返回更有意义的自定义表示(幸运的是,PowerShell cmdlet返回的类型经常出现这种情况)。

选择值的属性以在字符串中表示它的一个简单示例:

# Sample hashtable containing a value of a non-built-in type,
# [System.Diagnostics.Process]    
$ht = @{ one = 1; two = $(Get-Process -ID $PID) }

# Use the `.Path` property to represent the value.
$ht.GetEnumerator()  | % { "$($_.Name)=$($_.Value.Path)" }

答案 1 :(得分:4)

[string[]]$l_array = $l_table | out-string -stream

答案 2 :(得分:2)

哈希只是一个哈希表,所以它有一个键和一个值属性。

$hash = @{}

$hash["foo"] = "bob"

$hash.Values

$hash.Values | Out-string

如果您想获得枚举器,它将返回keyvaluepair

$hash.GetEnumerator() |%{$_ | out-string}

答案 3 :(得分:1)

虽然原始发帖人可能想要一个与 Format-Table 的输出相对应的字符串数组,但由于提供的尝试和发帖人自己的答案/评论可能暗示,问题标题的措词是更典型的是希望将哈希表本身转换为每个项目的值的数组(如果尚未转换为String,则转换为String)。对于那些寻求解决此问题的人,我提出以下内容(因为到目前为止似乎还没有类似的问题):-

简单的答案是使用

[string[]]$l_table.values

这确实提供了所需的字符串数组。

注意:$l_table.values[System.Collections.Hashtable+ValueCollection],因此即使值已经是字符串,也必须转换为[string[]]。例如,

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

没有它就无法工作。 (另一个可能的问题在下面提到。)

$l_table.values的主要缺陷在于,除非将哈希表定义为[ordered](PSv3 +),否则项目的顺序是不确定的(并且可以在修改哈希表时更改) 。通常,在将哈希表转换为数组时,需要对该数组中的元素进行某种排序。确实,有时键是(正)整数,目的是使所得数组使用与数组索引相同的值(请参见上面的$matches示例)。要创建这种类型的数组,请使用

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

或者,如果值已经是字符串,则只是

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

调用Powershell的集合切片功能(从而单个表达式可以通过使用数组表达式作为索引来生成独立选择的集合项的数组。例如$array[1,3,5,9]$array[1,2,3,4,5]$array[1..5] )。请注意,如果键形成一个从0开始的连续范围,则只会生成一个以键为索引的数组。但是,由于索引表达式是一个管道,因此可以获取所需键数组几乎所有的内容。要从“稀疏”哈希表(非字符串值)中获取结果数组,请使用

[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
#

现在,通过将任何居间(未使用)的数组项设置为“”(即[string]$null),结果数组将具有与相应索引值正确对应的整数键。如果这是一个问题,则可以使用两步过程来保留“缺失”条目 为$null。首先,通过一次使用一对字典对(使用GetEnumerator()来构建一个新的哈希表,将非字符串哈希表转换为字符串而不添加条目。其次,在将(现在为字符串)哈希表转换为数组时,请不要使用[string[]]来将$null保留在“未使用”项中,如下所示

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

或更有效(通过删除可能代价高昂的排序)

($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]})

注意:对于字符串值的稀疏哈希表,其初始形式无需转换

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

可以使用,但是如果需要,使用[string[]]会将所有丢失的条目从$null更改为""

答案 4 :(得分:0)

这是一个常见的问题;必须通过键或值检索Hashtable,但是你无法获得对的集合 - 毕竟这是原始哈希表。在我的例子中,哈希表由“字典”表示(你会记得来自VBS :-)。但是,您需要确定一个用于分隔键和分隔符的分隔符。值,在这种情况下为“Key&lt; - &gt; Value”

$ARRAY = ( $DICT.Keys | foreach-object { "$_<->$($DICT[$_])"})

如果需要,您甚至可以先对键进行排序。在这种情况下,我将其反转为Value&lt; ---&gt; Key并按值排序。我还将字符串扩展了一点,以使其更加冗长但清晰易读:

$ARRAY = ( $DICT.Keys | foreach-object { $DICT[$_] + "<--->" + $_} | sort-object)