Get index of object in Generic/List based on value of a property

Viewed 1134

I can populate a Generic.List with instances of my class, each with a unique value in the ID property, like this.

$packages = [System.Collections.Generic.List[object]]::New()

class Package {
    # Properties
    [String]$ID

    # Constructor
    Package ([String]$id) {
        $this.ID = $id
    }
}

foreach ($i in 65..90) {
    $packages.Add([Package]::New("$([char]$i)"))
}

Now I want to get the index of a particular item, along the lines of $packages.IndexOf('C'). But doing this in C# seems to require the use of a lambda, and PowerShell doesn't seem to support that. I would rather not have to initialize my own index variable and iterate through all the items in the list checking their IDs and incrementing the index along the way. But, maybe this is that grey area between using PowerShell with only native PS cmdlets and just using C#, where you miss out on the sugar in both extremes and have to make your own?

1 Answers

You can use a [scriptblock] as a predicate:

$packages.FindIndex({$args[0].ID -eq 'C'})
# or
$packages.FindIndex({param($item) $item.ID -eq 'C'})

Assuming your package IDs are unique, consider using a dictionary instead of a list:

$packages = [System.Collections.Generic.Dictionary[string,Package]]::new([StringComparer]::InvariantCultureIgnoreCase)

class Package {
    # Properties
    [String]$ID

    # Constructor
    Package ([String]$id) {
        $this.ID = $id
    }
}

foreach ($i in 65..90) {
    $ID = "$([char]$i)"
    $packages.Add($ID, [Package]::new($ID))
}

Now you don't need to worry about the position of the item, anymore, now you can simply remove one by ID:

$wasRemoved = $packages.Remove("C")

Remove() returns $true when it successfully removes an entry, $false when the key wasn't found

Related