我无法获得完全相同对象的多个元素的当前元素的索引:
$b = "A","D","B","D","C","E","D","F"
$b | ? { $_ -contains "D" }
替代版本:
$b = "A","D","B","D","C","E","D","F"
[Array]::FindAll($b, [Predicate[String]]{ $args[0] -contains "D" })
这将返回: d d d
但是这段代码:
$b | % { $b.IndexOf("D") }
替代版本:
[Array]::FindAll($b, [Predicate[String]]{ $args[0] -contains "D" }) | % { $b.IndexOf($_) }
返回:
1 1 1
所以它指向第一个元素的索引。 如何获取其他元素的索引?
答案 0 :(得分:10)
你可以这样做:
$b = "A","D","B","D","C","E","D","F"
(0..($b.Count-1)) | where {$b[$_] -eq 'D'}
1
3
6
答案 1 :(得分:4)
mjolinor's answer 概念优雅,但大型数据慢,大概是因为必须首先建立一个并行的索引数组(这也是内存 - 低效)。
它在概念上类似于以下基于LINQ的解决方案(PSv3 +),它具有更高的内存效率和大约两倍的速度,但仍然很慢:
$arr = 'A','D','B','D','C','E','D','F'
[Linq.Enumerable]::Where(
[Linq.Enumerable]::Range(0, $arr.Length),
[Func[int, bool]] { param($i) $arr[$i] -eq 'D' }
)
虽然与编译语言相比,任何 PowerShell循环解决方案最终都很慢,但对于大型数组,以下替代方案(更详细)仍然更快/强>:
PS C:\> & { param($arr, $val)
$i = 0
foreach ($el in $arr) { if ($el -eq $val) { $i } ++$i }
} ('A','D','B','D','C','E','D','F') 'D'
1
3
6
注意:
也许令人惊讶的是,此解决方案甚至比Matt's solution更快,后者在循环中调用[array]::IndexOf()
而不是枚举所有元素。
使用脚本块(使用调用操作符&
和参数调用)虽然不是绝对必要,但用于防止使用辅助变量$i
污染封闭范围。
foreach
语句比Foreach-Object
cmdlet (其内置别名为%
和,令人困惑的是,foreach
)。
简单地(隐式地)为每个匹配输出$i
会使PowerShell在数组中收集多个结果。
[int]
实例;将整个命令包装在@(...)
中,以确保始终获得一个数组。虽然$i
本身会输出$i
的值,但设计中的++$i
却没有(尽管如果需要,您可以使用(++$i)
来实现此目的)
与Array.IndexOf()
不同,PowerShell的-eq
运算符默认情况下为case- 不敏感;区分大小写,请改用-ceq
。
将上述内容转换为(简单的)函数很容易(请注意,为了灵活性,这些参数是故意无类型的):
function get-IndicesOf($Array, $Value) {
$i = 0
foreach ($el in $Array) {
if ($el -eq $Value) { $i }
++$i
}
}
# Sample call
PS C:\> get-IndicesOf ('A','D','B','D','C','E','D','F') 'D'
1
3
6
答案 2 :(得分:1)
你仍然需要使用[array]
中的静态方法循环,但是如果你仍然好奇,那么这样的东西就可以了。
$b = "A","D","B","D","C","E","D","F"
$results = @()
$singleIndex = -1
Do{
$singleIndex = [array]::IndexOf($b,"D",$singleIndex + 1)
If($singleIndex -ge 0){$results += $singleIndex}
}While($singleIndex -ge 0)
$results
1
3
6
循环直到找不到匹配项。首先通过将$singleIndex
指定为-1(这是非匹配将返回的内容)来假设匹配。找到匹配项时,将索引添加到结果数组中。