In PowerShell is there a way to return the index of an array with substring of a string

Viewed 1080

Is there another way return the indices of every instance of a substring in an array besides old fashioned looping through indices?

$myarray = @('herp','dederp','dedoo','flerp')
$substring = 'erp'
$indices = @()
for ($i=0; $i -lt $myarray.length; $i++) {
    if ($myarray[$i] -match $substring){
       $indices = $indices + $i
   }
}


$thisiswrong = @($myarray.IndexOf($substring))

The conditional inside that kind of for loop is kinda cumbersome, and $thisiswrong only ever gets a value of [-1]

2 Answers

You can use LINQ (adapted from this C# answer):

$myarray = 'herp', 'dederp', 'dedoo', 'flerp'
$substring = 'erp'

[int[]] $indices = [Linq.Enumerable]::Range(0, $myarray.Count).
                     Where({ param($i) $myarray[$i] -match $substring })

$indices receives 0, 1, 3.


As for what you tried:

$thisiswrong = @($myarray.IndexOf($substring))

System.Array.IndexOf only ever finds one index and matches entire elements, literally and case-sensitively in the case of strings.


There's a more PowerShell-like, but much slower alternative, as hinted at by js2010's answer; you can take advantage of the fact that the match-information objects that Select-String outputs have a .LineNumber property, reflecting the 1-based index of the position in the input collection - even if the input doesn't come from a file:

$myarray = 'herp', 'dederp', 'dedoo', 'flerp'
$substring = 'erp'

[int[]] $indices = 
  ($myarray | Select-String $substring).ForEach({ $_.LineNumber - 1 })

Note the need to subtract 1 from each .LineNumber value to get the 0-based array indices, and the use of the .ForEach() array method, which performs better than the ForEach-Object cmdlet.

If it was a file...

get-content file | select-string erp | select line, linenumber

Line   LineNumber
----   ----------
herp            1
dederp          2
flerp           4
Related