Array.Find on powershell array

前端 未结 5 863
耶瑟儿~
耶瑟儿~ 2021-02-13 11:28

How can I use the Array.Find method in powershell?

For example:

$a = 1,2,3,4,5
[Array]::Find($a, { args[0] -eq 3 })

gives



        
相关标签:
5条回答
  • 2021-02-13 11:53

    This was run across ~6 million items in a system.array using both methods

    $s=get-date
    $([array]::FindALL($OPTArray,[Predicate[string]]{ $args[0] -match '^004400702(_\d{5})?' })).count
    $(New-TimeSpan -Start $s -End $(get-date)).TotalSeconds
    
    20 items
    33.2223219 seconds
    
    $s=get-date
    $($OPTArray | where { $_ -match '^004400702(_\d{5})?'}).count 
    $(New-TimeSpan -Start $s -End $(get-date)).TotalSeconds
    
    20 items
    102.1832173 seconds
    
    0 讨论(0)
  • 2021-02-13 11:56

    Trevor Sullivan's answer is the right one, not only for Find() static method, but for FindIndex() as well.

    When you've got several NIC cards with both ipv4 & ipv6 active on your servers and want to check the ipv4 IP/netmask pairs, something like this is good :

    $NetworkAdapters = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'IPEnabled = True' | Select-Object -Property Description, IPAddress, IPSubnet, DefaultIPGateway, DNSServerSearchOrder, DNSDomain
    $NetworkAdapters | % {
      "Adapter {0} :" -f $_.Description
      # array'ing to avoid failure against single homed netcards
      $idx = [System.Array]::FindIndex(@($_.IPAddress), [Predicate[string]]{ $args[0] -match "\d+.\d+.\d+.\d+" })
      "  IP {0} has netmask {1}" -f @($_.IPAddress[$idx]), @($_.IPSubnet)[$idx]
    }
    

    My point is it works like a charm on 2012 WinPE, and fails on a production Win7 wks. Anyone got an idea ?

    0 讨论(0)
  • 2021-02-13 12:04

    There is no need to use Array.Find, a regular where clause would work fine:

    $a = @(1,2,3,4,5)
    $a | where { $_ -eq 3 }
    

    Or this (as suggested by @mjolinor):

    $a -eq 3
    

    Or this (returns $true or $false):

    $a -contains 3
    

    Where clause supports any type of objects, not just basic types, like this:

    $a | where { $_.SomeProperty -eq 3 }
    
    0 讨论(0)
  • 2021-02-13 12:06

    You need to cast the ScriptBlock as a Predicate[T]. Consider the following example:

    [Array]::Find(@(1,2,3), [Predicate[int]]{ $args[0] -eq 1 })
    # Result: 1
    

    The reason that you received the error, is because there was no matching method overload, in the case where you're passing in a PowerShell ScriptBlock. As you noted in your Get-Member output, there is no Find() method overload that accepts a ScriptBlock as its second parameter.

    [Array]::Find(@(1,2,3), { $args[0] -eq 1 })
    

    Cannot find an overload for "Find" and the argument count: "2". At line:1 char:17 + [Array]::Find(@(1,2,3), { $_ -eq 1 }) + ~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodException + FullyQualifiedErrorId : MethodCountCouldNotFindBest

    0 讨论(0)
  • 2021-02-13 12:09

    Another option would be using an ArrayList, which provides a Contains method:

    PS C:\> [Collections.ArrayList]$a = 'a', 'b', 'c'
    PS C:\> $a.Contains('b')
    True
    PS C:\> $a.Contains('d')
    False

    Or, as @Neolisk mentioned in the comments, you could use PowerShell's -contains operator:

    PS C:\> $a = 'a', 'b', 'c'
    PS C:\> $a -contains 'b'
    True
    PS C:\> $a -contains 'd'
    False
    0 讨论(0)
提交回复
热议问题