Эквивалент PowerShell метода LINQ SelectMany
Я пишу код PowerShell, чтобы получить все локальные адреса IPv4, исключая loopback one. Мне нужно что-то вроде метода 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
}
Ответы
Ответ 1
Вы можете сделать это, если объединить Foreach-Object
и Where-Object
следующим образом:
$ipaddresses = @(
Get-WmiObject Win32_NetworkAdapterConfiguration |
? { $_.IPAddress -ne $null } |
% { $_.IPAddress } |
? { $_ -notlike "127.*" -and $_ -notlike "*::*" })
Обратите внимание на @(...)
. Это приводит к тому, что если результат внутри конвейера ничто, пустой массив присваивается $ipaddresses
.
Ответ 2
Просто чтобы ответить на вопрос из темы
"эквивалент 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
Ответ 3
Я бы также упомянул, что эквивалент PowerShell SelectMany - Select-Object -ExpandProperty <property name of a collection>
. Однако это не очень хорошо работает с этим примером, потому что свойство IPAddress
является массивом строки. Сглаживание этого массива строковых произведений отдельными строками с другими прикрепленными свойствами, например:
Get-WmiObject Win32_NetworkAdapterConfiguration | Where {$_.IPAddress} |
Select Description -Expand IPAddress
К сожалению, PowerShell рассматривает объекты System.String
специально, и в результате он не хочет отображать ничего, кроме строкового значения (в этом случае IPAddress). Получение его для отображения других свойств (описание в этом примере) нецелесообразно (возможно?) AFAICT.
Ответ 4
Лучше поздно, чем никогда.
Я пришел к следующему методу (код представляет собой сочетание 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[]][email protected]{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[]][email protected]{id=1;name='ivan'},@{id=2;name='vasilij'},@{id=3;name='pjotr'}
[hashtable[]][email protected]{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
}