ChatGPT解决这个技术问题 Extra ChatGPT

在 PowerShell 循环中获取当前项目的索引

给定 PowerShell 中的项目列表,如何从循环中找到当前项目的索引?

例如:

$letters = { 'A', 'B', 'C' }

$letters | % {
  # Can I easily get the index of $_ here?
}

所有这一切的目标是我想使用 Format-Table 输出一个集合并添加一个带有当前项目索引的初始列。通过这种方式,人们可以交互地选择要选择的项目。


K
Keith Hill

.NET 在 System.Array 中为这类事情提供了一些方便的实用方法:

PS> $a = 'a','b','c'
PS> [array]::IndexOf($a, 'b')
1
PS> [array]::IndexOf($a, 'c')
2

评论中关于上述方法的要点。除了“只是”在数组中查找项目的索引之外,考虑到问题的上下文,这可能更合适:

$letters = { 'A', 'B', 'C' }
$letters | % {$i=0} {"Value:$_ Index:$i"; $i++}

Foreach (%) 可以有一个执行一次的 Begin sciptblock。我们在那里设置了一个索引变量,然后我们可以在进程脚本块中引用它,在退出脚本块之前它会递增。


此外,您可能不想在迭代这些项目时查找数组项目的每个索引。那将是对每个项目的线性搜索;听起来像是进行一次迭代 O(n^2) :-)
如果您确定始终有一个数组,则 IndexOf 有效,但即使 $letters 最终只是一个对象而不是数组,$letters | % {$i=0}... 方法也是安全的。
P
Peter Mortensen

我不确定是否可以使用“自动”变量。你总是可以为自己声明一个并增加它:

$letters = { 'A', 'B', 'C' }
$letters | % {$counter = 0}{...;$counter++}

或者改用 for 循环...

for ($counter=0; $counter -lt $letters.Length; $counter++){...}

示例:> "A,B,C,D,E,F,G" -split "," | % { $i = 0 } { if ( $i -gt 3 ) { $_ }; ++$i } 输出:E F G
当我不得不用计数器重命名文件时,它就像一个魅力~ dir | % {$i = 46}{ move-item $_ ("ARM-{0:00000}.pdf" -f $i++)}
$letters | % {$counter... 选项是安全的,即使 $letters 只是一个对象而不是数组,因为 for 选项不能正确处理它。
谢谢你 - 我从来没有见过在 foreach 后面有两组花括号的语法。它解决了像这样匹配两个数组的问题:$selected = $true,$false,$true; @('first','second','third') | % {$i=0}{If($selected[$i]){$_};$i++ } 返回“第一”和“第三”
这是 foreach-object -Begin {first block} -Process {second block} 的“快捷方式”。第一个块在处理之前运行一次,第二个块为每个要处理的项目运行。有关详细信息,请参阅 get-help foreach-item -full
P
Peter Mortensen

对于 PowerShell 3.0 及更高版本,内置了一个 :)

foreach ($item in $array) {
    $array.IndexOf($item)
}

这是找到匹配数组中每个项目的第一个项目的索引,而不是使用索引值迭代。这比较慢,如果数组包含重复项,您将获得错误的索引。
S
Shay Levy
0..($letters.count-1) | foreach { "Value: {0}, Index: {1}" -f $letters[$_],$_}

这很干净,但是太糟糕了,没有不涉及在数组中搜索索引的直接方法。
J
Jared Forth

对于像我一样从 Google 来到这里的人,Powershell 的更高版本有一个 $foreach 自动变量。您可以使用 $foreach.Current 找到“当前”对象


大多数人使用 $_ 表示当前对象。此外,OP 的问题是关于查找当前对象的索引,而不是对象本身。