about_Hash_Tables

简短说明

介绍如何在 PowerShell 中创建、使用哈希表以及对哈希表进行排序。

长说明

一 hashtable个也称为字典或关联数组的紧凑数据结构,用于存储一个或多个键值对。 例如,哈希表可能包含一系列 IP 地址和计算机名,其中 IP 地址是键,计算机名是值,反之亦然。

在 PowerShell 中,每个 hashtable 对象都是一个 [System.Collections.Hashtable] 对象。 可以在 PowerShell 中使用 Hashtable 对象的属性和方法。

从 PowerShell 3.0 开始,可以使用 [ordered] 类型加速器在 PowerShell 中创建 [System.Collections.Specialized.OrderedDictionary] 对象。

有序字典与哈希表的不同之处在于,键始终按照其列出顺序出现。 键的顺序 hashtable 不是确定性的。

哈希表中的键和值也是 .NET 对象。 它们通常是字符串或整数,但可以采用任何对象类型。 还可以创建嵌套哈希表,其中键的值是另一个 hashtable。

哈希表通常用于查找和检索数据。 可以使用哈希表来存储列表以及在 PowerShell 中创建计算属性。 并且,cmdlet 会将ConvertFrom-StringData结构化字符串数据转换为 .hashtable

语法

语法 hashtable 如下所示:

@{ <name> = <value>; [<name> = <value> ] ...}

有序字典的语法如下:

[ordered]@{ <name> = <value>; [<name> = <value> ] ...}

PowerShell 3.0 中引入了 [ordered] 类型加速器。

若要创建, hashtable请遵循以下准则:

  • 从 hashtable 登录名 (@) 开始。
  • 将大括号括起来 hashtable ({})。
  • 为内容 hashtable输入一个或多个键值对。
  • 使用等号 (=) 分隔每个键与其值。
  • 使用分号 (;) 或换行符分隔键值对。
  • 包含空格的键必须括在引号中。 值必须是有效的 PowerShell 表达式。 即使字符串不包含空格,也必须在引号中显示。
  • 若要管理, hashtable请将它保存在变量中。
  • 将排序 hashtable 分配给变量时,请将 [ordered] 类型放在符号之前 @ 。 如果将其放在变量名称之前,命令将会失败。

可以像使用哈希表一样使用有序字典。 任一类型都可以用作采用或 hashtable 字典 (iDictionary) 类型对象的参数的值。

创建哈希表和有序字典

请考虑以下 hashtable 和有序的字典示例:

$hash = @{
    1       = 'one'
    2       = 'two'
    'three' = 3
}
$hash
Name                           Value
----                           -----
three                          3
2                              two
1                              one

如你所看到的,未按定义键值对的顺序显示键值对 hashtable 。

创建有序字典的最简单方法是使用 [ordered] 属性。 将属性放在符号前面 @

$dictionary = [ordered]@{
    1       = 'one'
    2       = 'two'
    'three' = 3
}
$dictionary
Name                           Value
----                           -----
1                              one
2                              two
three                          3

与哈希表不同,有序字典维护键值的顺序。

转换哈希表和有序字典

不能使用 [ordered] 类型加速器转换或强制转换 hashtable。 如果将有序属性放在变量名称之前,则命令会失败并显示以下错误消息。

[ordered]$orderedhash = @{}
ParserError:
Line |
   1 |  [ordered]$orderedhash = @{}
     |  ~~~~~~~~~~~~~~
     | The ordered attribute can be specified only on a hash literal node.

若要更正表达式,请移动 [ordered] 属性。

$orderedhash = [ordered]@{}

可以将有序字典强制转换为 a hashtable,但不能保证成员的顺序。

[hashtable]$newhash = [ordered]@{
    Number = 1
    Shape = "Square"
    Color = "Blue"
}
$newhash
Name                           Value
----                           -----
Color                          Blue
Shape                          Square
Number                         1

Hashtable 和字典属性

哈希表和有序字典共享多个属性。 $hash请考虑前面示例中定义的变量和$dictionary变量。

$hash | Get-Member -MemberType Properties, ParameterizedProperty
   TypeName: System.Collections.Hashtable

Name           MemberType            Definition
----           ----------            ----------
Item           ParameterizedProperty System.Object Item(System.Object key) {get;set;}
Count          Property              int Count {get;}
IsFixedSize    Property              bool IsFixedSize {get;}
IsReadOnly     Property              bool IsReadOnly {get;}
IsSynchronized Property              bool IsSynchronized {get;}
Keys           Property              System.Collections.ICollection Keys {get;}
SyncRoot       Property              System.Object SyncRoot {get;}
Values         Property              System.Collections.ICollection Values {get;}
$dictionary | Get-Member -MemberType Properties, ParameterizedProperty
   TypeName: System.Collections.Specialized.OrderedDictionary

Name           MemberType            Definition
----           ----------            ----------
Item           ParameterizedProperty System.Object Item(int index) {get;set;},
                                     System.Object Item(System.Object key) {get;set;}
Count          Property              int Count {get;}
IsFixedSize    Property              bool IsFixedSize {get;}
IsReadOnly     Property              bool IsReadOnly {get;}
IsSynchronized Property              bool IsSynchronized {get;}
Keys           Property              System.Collections.ICollection Keys {get;}
SyncRoot       Property              System.Object SyncRoot {get;}
Values         Property              System.Collections.ICollection Values {get;}

最常用的属性是 CountKeysValuesItem

  • 指示 对象中的键值对数的 Count 属性。

  • Keys 属性是或字典中hashtable键名称的集合。

    PS> $hash.Keys
    three
    2
    1
    
    PS> $dictionary.Keys
    1
    2
    three
    
  • Values 属性是或字典中hashtable值的集合。

    PS> $hash.Values
    3
    two
    one
    
    PS> $dictionary.Values
    one
    two
    3
    
  • Item 属性是一个参数化属性,返回指定的项的值。 哈希表使用键作为参数化属性的参数,而字典默认使用索引。 此差异会影响访问每种类型的值的方式。

访问值

可通过两种常见方法来访问或 hashtable 字典中的值:成员表示法或数组索引表示法。

  • 成员表示法 - 可以使用键名称作为对象的成员属性来访问值。 例如:

    PS> $hash.1
    one
    
    PS> $dictionary.2
    two
    
  • 数组索引表示法 - 可以使用索引表示法访问值。 PowerShell 将该表示法转换为对 对象的 Item 参数化属性的调用。

    将索引表示法用于哈希表时,括号内的值为键名称。 如果键是字符串值,请将键名称括在引号中。 例如:

    PS> $hash['three']
    3
    
    PS> $hash[2]
    2
    

    在此示例中,键值 2 不是值集合中的索引。 它是键值对中的键值。 可以通过索引到值的集合来证明这一点。

    PS> ([array]$hash.Values)[2]
    one
    

    在字典中使用索引表示法时,括号内的值会根据其类型进行解释。 如果值为整数,则将其视为值集合中的索引。 如果值不是整数,则它被视为键名称。 例如:

    PS> $dictionary[1]
    two
    PS> ([array]$dictionary.Values)[1]
    two
    PS> $dictionary[[object]1]
    one
    PS> $dictionary['three']
    3
    

    在此示例中,数组值 [1] 是使用 Item(int index) 参数化属性重载的值集合中的索引。 数组值 [[object]1] 不是索引,而是使用重载的 Item(System.Object key) 键值。

    注意

    当键值为整数时,此行为可能会令人困惑。 如果可能,应避免在字典中使用整数键值。

处理属性名称冲突

如果键名称与类型的属性名称 HashTable 之一冲突,则可以使用 psbase 内部成员 访问这些属性。 例如,如果键名称是 keys 并且想要返回键的 HashTable 集合,请使用以下语法:

$hashtable.psbase.Keys

此要求适用于实现 System.Collections.IDictionary 接口的其他类型,例如 OrderedDictionary

迭代键和值

可以循环访问键, hashtable 以多种方式处理值。 本部分的每个示例都会生成相同的输出。 它们迭代此处定义的 $hash 变量:

$hash = [ordered]@{ Number = 1; Shape = "Square"; Color = "Blue"}

注意

在这些示例中, $hash 定义为有序字典,以确保输出始终按相同的顺序。 这些示例适用于标准哈希表,但输出的顺序不可预测。

每个示例针对每个键及其值返回一条消息:

The value of 'Number' is: 1
The value of 'Shape' is: Square
The value of 'Color' is: Blue

此示例使用块 foreach 循环访问密钥。

foreach ($Key in $hash.Keys) {
    "The value of '$Key' is: $($hash[$Key])"
}

此示例使用 ForEach-Object 来迭代键。

$hash.Keys | ForEach-Object {
    "The value of '$_' is: $($hash[$_])"
}

此示例使用 GetEnumerator() 该方法通过管道 ForEach-Object将每个键值对发送到 。

$hash.GetEnumerator() | ForEach-Object {
    "The value of '$($_.Key)' is: $($_.Value)"
}

此示例使用 GetEnumerator()ForEach() 方法循环访问每个键值对。

$hash.GetEnumerator().ForEach({"The value of '$($_.Key)' is: $($_.Value)"})

添加和删除键与值

通常,在创建密钥 hashtable 值对时,请在定义中包含键值对。 但是,可以随时添加 hashtable 和删除键值对。 以下示例创建一个空 hashtable的 。

$hash = @{}

可以使用数组表示法添加键值对。 例如,以下示例向 添加一个Time值为 的Nowhashtable键。

$hash["Time"] = "Now"

还可以使用Add()对象的方法System.Collections.Hashtable 添加键和值。 Add() 方法采用以下语法:

Add(Key, Value)

例如,若要添加值为 Time/> 的Nowhashtable键,请使用以下语句格式。

$hash.Add("Time", "Now")

此外,还可以使用加法运算符 (+) hashtable 向hashtable现有hashtable运算符添加键和值。 例如,以下语句将一个Time键添加到变量$hash中的值Nowhashtable。

$hash = $hash + @{Time="Now"}

还可以添加存储在变量中的值。

$t = "Today"
$now = (Get-Date)

$hash.Add($t, $now)

不能使用减法运算符从哈希表中删除键值对,但可以使用 Remove() 对象的方法 hashtable 。 Remove 方法采用以下语法:

$object.Remove(<key>)

以下示例从Time$hash中删除键值对。

$hash.Remove("Time")

哈希表中的对象类型

一个 hashtable 中的键和值可以具有任何 .NET 对象类型,一 hashtable 个可以具有多个类型的键和值。

以下语句创建 hashtable 进程名称字符串和进程对象值,并将其保存在变量中 $p

$p = @{
    "PowerShell" = (Get-Process PowerShell)
    "Notepad" = (Get-Process notepad)
}

可以显示 hashtable in $p 并使用键名称属性来显示值。

PS> $p

Name                           Value
----                           -----
PowerShell                     System.Diagnostics.Process (PowerShell)
Notepad                        System.Diagnostics.Process (notepad)

PS> $p.PowerShell

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    441      24    54196      54012   571     5.10   1788 PowerShell

PS> $p.keys | ForEach-Object {$p.$_.handles}
441
251

中的 hashtable 键可以是任何 .NET 类型。 以下语句将键值对添加到 hashtable 变量中 $p 。 键是代表 WinRM 服务的 Service 对象,值是服务的当前状态

$p = $p + @{
    (Get-Service WinRM) = ((Get-Service WinRM).Status)
}

可以使用与用于其他 hashtable对的方法相同的方法来显示和访问新的键值对。

PS> $p

Name                           Value
----                           -----
PowerShell                     System.Diagnostics.Process (PowerShell)
Notepad                        System.Diagnostics.Process (notepad)
System.ServiceProcess.Servi... Running

PS> $p.keys
PowerShell
Notepad

Status   Name               DisplayName
------   ----               -----------
Running  winrm              Windows Remote Management (WS-Manag...

PS> $p.keys | ForEach-Object {$_.name}
WinRM

键 hashtable 和值也可以是 Hashtable 对象。 以下语句将键值对添加到 hashtable 键是字符串、Hash2 的变量中的 $p 键值对,值是具有三个 hashtable 键值对。

$p = $p + @{
    "Hash2"= @{a=1; b=2; c=3}
}

可以使用相同的方法显示和访问新值。

PS> $p

Name                           Value
----                           -----
PowerShell                     System.Diagnostics.Process (pwsh)
Hash2                          {[a, 1], [b, 2], [c, 3]}
Notepad                        System.Diagnostics.Process (Notepad)
WinRM                          Running

PS> $p.Hash2

Name                           Value
----                           -----
a                              1
b                              2
c                              3

PS> $p.Hash2.b
2

对键和值进行排序

中的 hashtable 项本质上是无序的。 每次显示键值对时,它们可能会以不同的顺序显示。

虽然无法排序, hashtable但可以使用 GetEnumerator() 哈希表方法枚举键和值,然后使用 Sort-Object cmdlet 对枚举值进行排序以显示。

例如,以下命令枚举 $p 变量中哈希表的键和值,然后按字母顺序对键进行排序。

PS> $p.GetEnumerator() | Sort-Object -Property key

Name                           Value
----                           -----
Hash2                          {[a, 1], [b, 2], [c, 3]}
Notepad                        System.Diagnostics.Process (Notepad)
PowerShell                     System.Diagnostics.Process (pwsh)
WinRM                          Running

以下命令使用相同的过程按降序对哈希值进行排序。

PS> $p.GetEnumerator() | Sort-Object -Property Value -Descending

Name                           Value
----                           -----
PowerShell                     System.Diagnostics.Process (pwsh)
Notepad                        System.Diagnostics.Process (Notepad)
Hash2                          {[a, 1], [b, 2], [c, 3]}
WinRM                          Running

从哈希表创建对象

从 PowerShell 3.0 开始,可以从属性和属性值创建对象 hashtable 。

语法如下:

[<class-name>]@{
  <property-name>=<property-value>
  <property-name>=<property-value>
}

此方法仅适用于具有无参数构造函数的类。 对象属性必须是公共且可设置的。

有关详细信息,请参阅 about_Object_Creation

ConvertFrom-StringData

该 cmdlet 将 ConvertFrom-StringData 字符串或此处键值对的字符串转换为一个 hashtable。 可以在脚本的 Data 部分安全地使用 ConvertFrom-StringData cmdlet,并且可以将其与 Import-LocalizedData cmdlet 配合使用,以当前用户的用户界面 (UI) 区域性显示用户消息。

当包含引号中的 hashtable 值时,此处字符串特别有用。 有关 here-string 的详细信息,请参阅 about_Quoting_Rules

以下示例演示如何在上一示例中创建用户消息的此处字符串,以及如何使用 ConvertFrom-StringData 它们从字符串转换为字符串 hashtable。

以下命令创建键值对的 here-string,然后将其保存在 $string 变量中。

$string = @"
Msg1 = Type "Windows".
Msg2 = She said, "Hello, World."
Msg3 = Enter an alias (or "nickname").
"@

此命令使用 ConvertFrom-StringData cmdlet 将此处的字符串转换为 .hashtable

ConvertFrom-StringData $string

Name                           Value
----                           -----
Msg3                           Enter an alias (or "nickname").
Msg2                           She said, "Hello, World."
Msg1                           Type "Windows".

有关 here-string 的详细信息,请参阅 about_Quoting_Rules

另请参阅