2

I created a function to find an item in an array so I can update it.

  function Get-ArrayRowIndex {
                param(
                    [parameter(mandatory = $true)][array]$Property,
                    [parameter(mandatory = $true)][string]$Value
                )
           
                #Loop through array,incrementing index until value is found. Jordan wrote this and I refined it.
                [int]$index = 0
                while ($index -lt ($Property.count)) {
                    if ($Property[$index] -eq $Value) {
                        break
                    }
                    $index++
                }
                return [int]$index
            }

The problem is when the object is not found the function returns the total number of items in the array. How can I return an error if not found?

6
  • 1
    How about, after the loop, you test whether $index equals $Property.count and, if so, return an error? Commented Jan 5, 2022 at 22:01
  • 2
    You could also use the built-in System.Array.IndexOf Commented Jan 5, 2022 at 22:03
  • 2
    Good pointer, @adv12, but the caveat is that with strings .IndexOf() is case-sensitive, whereas PowerShell's operators (such as -eq) are case-insensitive. Commented Jan 5, 2022 at 22:12
  • just for my curiosity ... what do you need the index of an array object for? i usually grab the object itself. the .Where({}) array method is both fast and rather flexible. Commented Jan 6, 2022 at 1:37
  • 1
    @dcaz - try taking a look at the speed [and simplicity] of using $Collection.Where({Filter code here}) gives you. it otta be faster than hunting down an index to use later for accessing the desired object from an array. Commented Jan 6, 2022 at 17:21

3 Answers 3

4

If you want to throw an error in case the value isn't found:

function Get-ArrayRowIndex {
                param(
                    [parameter(mandatory = $true)][array]$Property,
                    [parameter(mandatory = $true)][string]$Value
                )
           
                [int]$index = 0
                while ($index -lt ($Property.count)) {
                    if ($Property[$index] -eq $Value) {
                        # Found -> output the value and return (exit) here.
                        return $index 
                    }
                    $index++
                }
                # Getting here means that the value wasn't found.
                throw "'$Value' not found in the given array."
            }

Note that you could use the [Array]::FindIndex() method instead of looping through the array yourself:

# Returns the index if found; -1 otherwise.
[Array]::FindIndex(
  $Property, 
  [Predicate[object]] { $Value -eq $args[0] }
)

[Array].IndexOf() is another option, but only if case-sensitive string comparison is desired (whereas PowerShell's operators, such as -eq used above, are case-insensitive by default); e.g., ('FOO', 'bar').IndexOf('foo') yields -1 (not found) and ('FOO', 'foo').IndexOf('foo') yields 1

Sign up to request clarification or add additional context in comments.

Comments

3

The PowerShell way, using Select-String:

$Properties = 'One', 'Two', 'Three'
$Value = 'Two'
($Properties | Select-String -SimpleMatch -Pattern $Value).LineNumber

2

Throwing errors:

$Found = $Properties | Select-String -SimpleMatch -Pattern $Value
Switch ($Found.Count) {
    0       { Throw "$Value not found" }
    1       { $Found.LineNumber }
    Default { Throw "More than one $Value found" }
}

1 Comment

Great - good job!
3

Normally a for loop is a cleaner approach for this:

function Get-ArrayRowIndex {
    param(
        [Parameter(Mandatory)]
        [array] $Property,

        [Parameter(Mandatory)]
        [string] $Value
    )

    for ($i = 0; $i -lt $Property.Count; $i++) {
        if ($Property[$i] -eq $Value) {
            return $i
        }
    }

    throw "$Value not found in this array."
}

$arr = 0..10
Get-ArrayRowIndex $arr 4  # => returns 4
Get-ArrayRowIndex $arr 11 # => throws "11 not found in this array."

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.