通过散列循环,或在PowerShell中使用数组?

Syl*_*via 86 powershell

我正在使用这个(简化的)代码块从SQL Server中使用bcp提取一组表.

$OutputDirectory = "c:\junk\"
$ServerOption =   "-SServerName"
$TargetDatabase = "Content.dbo."

$ExtractTables = @(
    "Page"
    , "ChecklistItemCategory"
    , "ChecklistItem"
)

for ($i=0; $i -le $ExtractTables.Length – 1; $i++)  {
    $InputFullTableName = "$TargetDatabase$($ExtractTables[$i])"
    $OutputFullFileName = "$OutputDirectory$($ExtractTables[$i])"
    bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
}
Run Code Online (Sandbox Code Playgroud)

它工作得很好,但现在有些表需要通过视图提取,有些则不需要.所以我需要一个像这样的数据结构:

"Page"                      "vExtractPage"
, "ChecklistItemCategory"   "ChecklistItemCategory"
, "ChecklistItem"           "vExtractChecklistItem"
Run Code Online (Sandbox Code Playgroud)

我在看哈希,但我找不到任何关于如何循环哈希的东西.这里做什么是正确的?也许只是使用一个数组,但两个值都用空格分隔?

还是我错过了一些明显的东西?

Ver*_*Ray 180

脚本不喜欢速记; 它的可读性较差.%{}运算符被认为是简写.以下是如何在脚本中完成可读性和可重用性:

变量设置

PS> $hash = @{
    a = 1
    b = 2
    c = 3
}
PS> $hash

Name                           Value
----                           -----
c                              3
b                              2
a                              1
Run Code Online (Sandbox Code Playgroud)

选项1:GetEnumerator()

注:个人喜好; 语法更容易阅读

GetEnumerator()方法将如下所示完成:

foreach ($h in $hash.GetEnumerator()) {
    Write-Host "$($h.Name): $($h.Value)"
}
Run Code Online (Sandbox Code Playgroud)

输出:

c: 3
b: 2
a: 1
Run Code Online (Sandbox Code Playgroud)

选项2:密钥

Keys方法将如下所示完成:

foreach ($h in $hash.Keys) {
    Write-Host "${h}: $($hash.Item($h))"
}
Run Code Online (Sandbox Code Playgroud)

输出:

c: 3
b: 2
a: 1
Run Code Online (Sandbox Code Playgroud)

附加信息

小心排序哈希表...

Sort-Object可能会将其更改为数组:

PS> $hash.GetType()

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


PS> $hash = $hash.GetEnumerator() | Sort-Object Name
PS> $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array
Run Code Online (Sandbox Code Playgroud)

这个和其他PowerShell循环可以在我的博客上找到.

  • @JamesQMurphy我从上面复制并粘贴了@ andy-arismendi提供的答案; 它是这个问题的流行管道解决方案.你的声明引起了我的兴趣,那就是'ForEach-Object`(又名:'%{}`)比`foreach`更快;**我表明不是更快**.我想证明你的观点是否有效; 因为我和大多数人一样,喜欢我的代码尽可能快地运行.现在,您的论点正在变为并行运行作业(可能使用多台计算机/服务器)......这当然比从单个线程串行运行作业更快.干杯! (4认同)
  • 像这样一个可读性,特别是对于像我这样没有奉献的PowerShell开发人员. (3认同)
  • 我同意这种方法更容易阅读,因此可能更适合编写脚本。 (2认同)
  • 除了可读性之外,VertigoRay的解决方案和Andy的解决方案之间存在一个区别.%{}是`ForEach-Object`的别名,它与此处的`foreach`语句不同.`ForEach-Object`使用管道,如果你已经在使用管道,这可以快得多.'foreach`声明没有; 这是一个简单的循环. (2认同)

And*_*ndi 97

Christian的答案效果很好,并展示了如何使用该GetEnumerator方法遍历每个哈希表项.您也可以循环使用该keys属性.以下是一个示例:

$hash = @{
    a = 1
    b = 2
    c = 3
}
$hash.Keys | % { "key = $_ , value = " + $hash.Item($_) }
Run Code Online (Sandbox Code Playgroud)

输出:

key = c , value = 3
key = a , value = 1
key = b , value = 2
Run Code Online (Sandbox Code Playgroud)

  • 为什么`$ hash.Item($ _)`而不是`$ hash [$ _]`? (4认同)
  • 你甚至可以使用`$ hash.$ _`. (4认同)
  • 如果哈希表包含 key = 'Keys',则此方法不起作用。 (2认同)

小智 10

您也可以在没有变量的情况下执行此操作

@{
  'foo' = 222
  'bar' = 333
  'baz' = 444
  'qux' = 555
} | % getEnumerator | % {
  $_.key
  $_.value
}
Run Code Online (Sandbox Code Playgroud)


Eel*_* L. 6

我更喜欢带有管道的枚举器方法上的这个变体,因为您不必在 foreach 中引用哈希表(在 PowerShell 5 中测试):

$hash = @{
    'a' = 3
    'b' = 2
    'c' = 1
}
$hash.getEnumerator() | foreach {
    Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Key = c and Value = 1
Key = b and Value = 2
Key = a and Value = 3
Run Code Online (Sandbox Code Playgroud)

现在,这不是故意按值排序的,枚举器只是以相反的顺序返回对象。

但由于这是一个管道,我现在可以对从枚举器接收到的对象进行排序:

$hash.getEnumerator() | sort-object -Property value -Desc | foreach {
  Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Key = a and Value = 3
Key = b and Value = 2
Key = c and Value = 1
Run Code Online (Sandbox Code Playgroud)

  • [“有序字典与哈希表的不同之处在于,键始终按照列出它们的顺序出现。哈希表中键的顺序不确定](https://learn.microsoft.com/en-us/ powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-6) - `[ordered]` 属性触发选择不同的实现。 (2认同)

CB.*_*CB. 5

关于循环哈希:

$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"}
$Q.GETENUMERATOR() | % { $_.VALUE }
1
3
2

$Q.GETENUMERATOR() | % { $_.key }
ONE
THREE
TWO
Run Code Online (Sandbox Code Playgroud)


use*_*625 5

这是另一种快速的方法,只需将键用作哈希表的索引即可获取值:

$hash = @{
    'a' = 1;
    'b' = 2;
    'c' = 3
};

foreach($key in $hash.keys) {
    Write-Host ("Key = " + $key + " and Value = " + $hash[$key]);
}
Run Code Online (Sandbox Code Playgroud)