HOWTO · PowerShell

如何在 PowerShell 中创建数组、哈希表和字典

通过本综合指南学习如何在 PowerShell 中创建和使用数组、哈希表和有序字典。了解主要区别、如何访问、添加和删除项,以及何时使用每种数据结构。包括实用示例、真实用例和常见问题部分,帮助你高效掌握 PowerShell 脚本和数据操作。无论是初学者还是希望提高 PowerShell 自动化和数据组织能力的进阶用户,都非常适合。

本页内容

对于一系列值,选择数组(@());对于键值查找,选择哈希表(@{});当必须保留键被添加的顺序时,选择有序字典([ordered]@{})。下面的示例是自包含的 PowerShell 片段。这些示例没有可用的运行时观察,因此不主张任何输出。

在 PowerShell 中创建数组

数组在一个变量中存储多个值。PowerShell 数组的索引从零开始,-1 指最后一个元素。@() 显式地将结果收集为数组,包括当命令返回单个值时。运行此示例:

$items = @('apple', 'banana', 'cherry')
$items[0]
$items[-1]
$items += 'date'
$items = @($items | Where-Object { $_ -ne 'banana' })
$items -join ', '

该示例读取第一个和最后一个值,追加一个值,然后赋值一个排除了 banana 的过滤后数组。PowerShell 数组大小固定;+= 会创建一个结果数组并将其赋值回去,因此反复向大数组追加可能需要反复复制。对于频繁的添加和删除,可变集合如 System.Collections.Generic.List[object] 可能更合适。要检查数组的类型,请使用 $items.GetType().FullName;对于这些字符串值,@() 产生的是 Object[]。

在 PowerShell 中使用哈希表

PowerShell 哈希表将键映射到值。用 @{} 创建一个,用括号表示法读取一个项,赋值一个键以添加或替换一个项,并调用 .Remove() 删除一个项。括号对任意键名都能可靠地工作;当键是一个简单的类似属性的名称时,点表示法很方便,但可能与 Count 等内置成员冲突。

$inventory = @{ Fruit = 'Apple'; Color = 'Red'; Count = 5 }
$inventory['Color']
$inventory['Shape'] = 'Round'
$inventory.Remove('Color')
$inventory.GetEnumerator() | Sort-Object Name | ForEach-Object {
    "{0}={1}" -f $_.Name, $_.Value
}

最后一个管道将输出的项按关键字排序以便显示。它不会对原始哈希表进行重新排序或替换。PowerShell 的哈希表键默认不区分大小写;当键的比较语义需要不同的时候,请使用其他集合。

在 PowerShell 中创建有序字典

[ordered] 字面量会创建一个有序字典,并保留项被插入的顺序。像在哈希表中一样,使用键访问和更新项。插入顺序不同于字母排序:除非你显式地对一个单独的结果进行排序,否则原始顺序仍然是插入序列。

$settings = [ordered]@{ Name = 'Delft'; Region = 'South Holland'; Active = $true }
$settings['Region']
$settings['Timezone'] = 'Europe/Amsterdam'
$settings.GetEnumerator() | ForEach-Object {
    "{0}={1}" -f $_.Key, $_.Value
}

哈希表与有序字典:主要区别

| 特征 | 哈希表 | 有序字典 |
| PowerShell 字面量 | @{} | [ordered]@{} |
| 数据模型 | 键映射到值 | 键映射到值 |
| 迭代顺序 | 不要依赖插入顺序 | 保留插入顺序 |
| 读取或更新一个项 | $table['key'] | $dictionary['key'] |
| 最适合 | 当显示顺序不重要时按 key 查找 | 插入顺序很重要的键值数据 |

PowerShell 哈希表并不等同于每一种 .NET 字典类型。System.Collections.Hashtable 是 PowerShell 的 @{} 字面量所使用的 .NET 类型,而 .NET 还提供了其他具有各自排序和比较行为的字典实现。请根据你的代码所需的具体类型和行为进行选择。不要在没有测量实际工作负载的情况下就断定任一集合更快。

实际用例

当输出应遵循所选顺序时,对用户或配置字段使用有序字典。使用哈希表按 key 对单词进行计数。这些示例展示了这两项任务;代码是独立的,不主张任何输出。

$user = [ordered]@{
    Name = 'John Doe'
    Email = 'johndoe@example.com'
    Role = 'Admin'
}
$user.GetEnumerator() | ForEach-Object { "{0}: {1}" -f $_.Key, $_.Value }

$text = 'apple banana apple orange apple banana'
$wordCount = @{}
$text.Split() | ForEach-Object {
    if ($wordCount.ContainsKey($_)) {
        $wordCount[$_] += 1
    } else {
        $wordCount[$_] = 1
    }
}
$wordCount.GetEnumerator() | Sort-Object Name | ForEach-Object {
    "{0}: {1}" -f $_.Name, $_.Value
}

结论

对于按位置处理的有序序列,使用数组;对于基于 key 的查找,使用哈希表;当插入序列本身就是你所呈现数据的一部分时,使用有序字典。请记住,数组的 += 会赋值一个新数组,过滤会返回一个需要赋值的结果,而对哈希表枚举出的项进行排序改变的是显示的结果,而不是表本身。

常见问题(FAQ)

PowerShell 中哈希表和字典有什么区别?

在日常的 PowerShell 使用中,“字典”可以描述一种通用的键值结构,而 @{} 会创建一个以 .NET 的 System.Collections.Hashtable 类型为基础的 PowerShell 哈希表。.NET 类库也有不同的字典类型,因此当 API 需要特定的实现时,请检查具体的类型。

如何向 PowerShell 数组添加或从中删除项?

用 $array += 'newItem' 追加,然后将结果赋值回变量。要删除匹配的值,请进行过滤并赋值结果,例如 $array = @($array | Where-Object { $_ -ne 'itemToRemove' })。这些操作产生的结果是一个数组;它们不会就地调整现有数组的大小。

我可以在 PowerShell 中对哈希表进行排序吗?

使用 $hash.GetEnumerator() | Sort-Object Name 对其项进行排序以便显示。这会返回排序后的项,并保持 $hash 不变。当你需要插入顺序时,请使用 [ordered]@{};它保留项被添加的顺序,而不是按字母顺序对键进行排序。