mjolinor's answer is conceptually elegant , but slow with large arrays , presumably because of the need to create a parallel array of indexes first (which is also memory inefficient).
It is conceptually similar to the following LINQ (PSv3 +) based solution , which is more memory efficient and about twice as fast, but still slow :
$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' } )
Although any PowerShell looping solution is ultimately slow compared to the compiled language, the next alternative, while more verbose , is still much faster with large arrays
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
Note:
Perhaps this unexpected solution is even faster than the Matt> solution, which calls [array]::IndexOf() in a loop instead of listing all the elements.
The use of a script block (called with the & operator and arguments), although not strictly necessary, is used to prevent infection of the surrounding area using the $i helper variable.
The foreach is faster than the Foreach-Object (whose built-in aliases are % and, vaguely, also foreach ).
The simple (implicit) output of $i for each match causes PowerShell to collect multiple results in an array.
- If only one index is found, instead you get a scalar
[int] ; complete the whole command in @(...) to make sure you always get an array.
While $i itself infers the value of $i , ++$i by design is NOT (although you could use (++$i) to achieve this if necessary).
Unlike Array.IndexOf() , the PowerShell -eq is not -eq by default; for case sensitivity, use -ceq .
It is easy to turn the above into a (simple) function (note that the parameters are set non-standard, for flexibility):
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