PowerShell-эквивалент метода LINQ SelectMany - PullRequest
20 голосов
/ 09 марта 2011

Я пишу код PowerShell, чтобы получить все локальные адреса IPv4, кроме петлевого.Мне нужно что-то вроде метода LINQ SelectMany, но я не могу понять, как это сделать с фильтрами PS.Это код, который у меня есть, который работает с использованием простого старого ArrayList:

function Get-Computer-IP-Address()
{
    $ipAddresses = New-Object System.Collections.ArrayList

    $networkAdaptersWithIp = Get-WmiObject Win32_NetworkAdapterConfiguration | ? { $_.IPAddress -ne $null }
    foreach ($networkAdapter in $networkAdaptersWithIp)
    {
        foreach ($ipAddress in $networkAdapter.IPAddress)
        {
            if ($ipAddress -notlike "127.*" -and $ipAddress -notlike "*::*")
            {
                $ipAddresses.Add($ipAddress)
            }
        }
    }

    if ($ipAddresses.Length -eq 0)
    {
        throw "Failed to find any non-loopback IPv4 addresses"
    }

    return $ipAddresses
}

Я хотел бы знать, есть ли более чистый способ сделать это с меньшим количеством кода.

Ответы [ 4 ]

21 голосов
/ 09 марта 2011

Вы можете сделать это, если объедините Foreach-Object и Where-Object следующим образом:

$ipaddresses = @(
  Get-WmiObject Win32_NetworkAdapterConfiguration | 
  ? { $_.IPAddress -ne $null } |
  % { $_.IPAddress } |
  ? { $_ -notlike "127.*" -and $_ -notlike "*::*" })

Обратите внимание на @(...).Это приводит к тому, что если результатом конвейера внутри является ничто , пустой массив присваивается $ipaddresses.

15 голосов
/ 27 июня 2013

Просто чтобы ответить на вопрос из темы «PowerShell-эквивалент метода LINQ SelectMany» :

collection.SelectMany(el => el.GetChildren()) // SelectMany in C#

эквивалентно

$collection | % { $_ }                    # SelectMany in PowerShell for array of arrays
$collection | % { $_.GetChildren() }      # SelectMany in PowerShell for complex object

Пример

$a = (1,2,3),('X','F'),'u','y'
$a.Length                # output is 4
($a | % { $_ }).Length   # output is 7

Другой пример

$dirs = dir -dir c:
$childFiles = $dirs | % { $_.GetFiles() }
$dirs.Length          # output is 6
$childFiles.Length    # output is 119
8 голосов
/ 09 марта 2011

Я бы также упомянул, что эквивалент PowerShell для SelectMany равен Select-Object -ExpandProperty <property name of a collection>. Однако это не очень хорошо работает с этим примером, потому что свойство IPAddress является массивом строк. Сглаживание этого массива строковых произведений отдельными строками с другими прикрепленными свойствами, например ::

Get-WmiObject Win32_NetworkAdapterConfiguration | Where {$_.IPAddress} | 
    Select Description -Expand IPAddress

К сожалению, PowerShell обрабатывает System.String объекты специально, и в результате он не хочет отображать ничего, кроме значения строки (в данном случае IP-адрес). Получение также отображения других свойств (описание в этом примере) не практично (возможно?) AFAICT.

0 голосов
/ 17 марта 2014

Лучше поздно, чем никогда. Я пришел к следующему методу (код представляет собой смесь PowerShell 2.0 и PowerShell 3.0):


    if(-not (test-path variable:psversiontable)){return}
    rv -ea silentlycontinue -force *
    cls
    $major=$psversiontable.psversion.major
    $linqenum=[linq.enumerable]
    'min:'+$linqenum::min([int[]](170..180))
    'max:'+$linqenum::max($linqenum::range(170,170))
    $membertypes=[reflection.membertypes]
    $bindflags=[reflection.bindingflags]
    [reflection.membertypes]$type=$membertypes::method
    [reflection.bindingflags]$attr=$bindflags::public,$bindflags::static
    $name='Min'
    $methods=$linqenum.getmember($name,$type,$attr)|?{$_.isgenericmethod}
    $method=$methods[0]
    $closed=$method.makegenericmethod((,[int]))
    "$name`:"+$closed.Invoke($null,(,[int[]](170..180)))
    $name='Max'
    $methods=$linqenum.getmember($name,$type,$attr)|?{$_.isgenericmethod}
    $method=$methods[0]
    $closed=$method.makegenericmethod((,[int]))
    "$name`:"+$closed.Invoke($null,(,$linqenum::range(170,170)))
    $name='SelectMany'
    $methods=$linqenum.getmember($name,$type,$attr)|?{$_.isgenericmethod}
    $method=$methods[0]
    #$params=[hashtable],[string]
    #$closed=$method.makegenericmethod($params)
    $closed=$method.makegenericmethod(([hashtable],[string]))
    [hashtable[]]$owners=@{name="Sidney";pets=("Scruffy","Sam")},
                         @{name="Ronen";pets=("Walker","Sugar")},
                         @{name="Hines";pets=(,"Dusty")},
                         @{name="Vernette";pets=("Scratches","Diesel")}
    if($major -eq 2){
     $delegate=[func[hashtable,collections.generic.ienumerable[string]]]
     $sb={param([hashtable]$owner) ,[string[]]$owner.pets}
    }else{
     $delegate=[func[hashtable,string[]]]
     $sb={param($owner) $owner.pets}
    }
    $selector=$sb -as $delegate
    $params=$owners,$selector
    $pets=$closed.Invoke($null,$params)
    "`n$name`n$('-'*$name.length)"
    $pets
    $method=$methods[3]
    $params=[hashtable],[string],[hashtable]
    $closed=$method.makegenericmethod($params)
    $resultsb={param($owner,$pet)@{owner=$owner.name;pet=$pet}}
    #$resultdelegate=[func[hashtable,string,hashtable]]
    #$result=$resultsb -as $resultdelegate
    $params=$owners,$selector,[func[hashtable,string,hashtable]]$resultsb
    $ownerpet=$closed.Invoke($null,$params)
    $ownerpet|select values|ft -auto
    if($major -gt 2){
     $linqenum::selectmany(
      $owners,
      [func[hashtable,string[]]]`
      {param($owner) $owner.pets},
      [func[hashtable,string,hashtable]]`
      {param($owner,$pet)@{owner=$owner.name;pet=$pet}}
     )|select values|ft -auto
     $linqenum::selectmany(
      [int[]](1..4),
      [func[int,int[]]]`
      {param($left) 11..(11+$left-1)},
      [func[int,int,hashtable]]`
      {param($left,$right)@{left=$left;right=$right}}
     )|select values|ft -auto
     $linqenum::selectmany(
      $linqenum::range(1,4),
      [func[int,int[]]]`
      {param($left) $linqenum::range(11,$left)},
      [func[int,int,hashtable]]`
      {param($left,$right)@{left=$left;right=$right}}
     )|select values|ft -auto
     $name='Join'
     [hashtable[]]$person=@{id=1;name='ivan'},@{id=2;name='vasilij'},@{id=3;name='pjotr'}
     [hashtable[]]$job=@{id=1;job='tokar'},@{id=1;job='pekar'},
                       @{id=2;job='doctor'},
                       @{id=3;job='soldat'},@{id=3;job='milicioner'},@{id=3;job='jurist'}
     "`n$name`n$('-'*$name.length)"
     [linq.enumerable]::join(
      $person,$job,
      [func[hashtable,int]]{param($p) $p.id},
      [func[hashtable,int]]{param($p) $p.id},
      [func[hashtable,hashtable,hashtable]]`
      {param($p,$j) @{name=$p.name;job=$j.job}}
     )|select values|ft -auto
    }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...