PowerShell equivalent of LINQ Any()?

2019-01-08 16:44发布

I would like to find all directories at the top level from the location of the script that are stored in subversion.

In C# it would be something like this

Directory.GetDirectories(".")
  .Where(d=>Directories.GetDirectories(d)
     .Any(x => x == "_svn" || ".svn"));

I'm having a bit of difficulty finding the equivalent of "Any()" in PowerShell, and I don't want to go through the awkwardness of calling the extension method.

So far I've got this:

 Get-ChildItem | ? {$_.PsIsContainer} | Get-ChildItem -force | ? {$_.PsIsContainer -and $_.Name -eq "_svn" -or $_.Name -eq ".svn"

This finds me the svn directories themselves, but not their parent directories - which is what I want. Bonus points if you can tell me why adding

 | Select-Object {$_.Directory}

to the end of that command list simply displays a sequence of blank lines.

11条回答
Rolldiameter
2楼-- · 2019-01-08 16:59

A variation on @JaredPar's answer, to incorporate the test in the Test-Any filter:

function Test-Any {
    [CmdletBinding()]
    param($EvaluateCondition,
        [Parameter(ValueFromPipeline = $true)] $ObjectToTest)
    begin {
        $any = $false
    }
    process {
        if (-not $any -and (& $EvaluateCondition $ObjectToTest)) {
            $any = $true
        }
    }
    end {
        $any
    }
}

Now I can write "any" tests like

> 1..4 | Test-Any { $_ -gt 3 }
True

> 1..4 | Test-Any { $_ -gt 5 }
False
查看更多
ら.Afraid
3楼-- · 2019-01-08 17:00

I recommend the following solution:

<#
.SYNOPSIS 
   Tests if any object in an array matches the expression

.EXAMPLE
    @( "red", "blue" ) | Where-Any { $_ -eq "blue" } | Write-Host
#>
function Where-Any 
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $True)]
        $Condition,

        [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
        $Item
    )

    begin {
        [bool]$isMatch = $False
    }

    process {
      if (& $Condition $Item) {
          [bool]$isMatch = $true
      }
    }

    end {
        Write-Output $isMatch
    }
}

# optional alias
New-Alias any Where-Any
查看更多
Juvenile、少年°
4楼-- · 2019-01-08 17:02

You can tighten this up a bit:

gci -fo | ?{$_.PSIsContainer -and `
            (gci $_ -r -fo | ?{$_.PSIsContainer -and $_ -match '[_.]svn$'})}

Note - passing $__.Name to the nested gci is unnecessary. Passing it $_ is sufficent.

查看更多
\"骚年 ilove
5楼-- · 2019-01-08 17:04

Unfortunately there is no equivalent in PowerShell. I wrote a blog post about this with a suggestion for a general purpose Test-Any function / filter.

function Test-Any() {
    begin {
        $any = $false
    }
    process {
        $any = $true
    }
    end {
        $any
    }
}

Blog post: Is there anything in that pipeline?

查看更多
SAY GOODBYE
6楼-- · 2019-01-08 17:08

You can use the original LINQ Any:

[Linq.Enumerable]::Any($list)
查看更多
beautiful°
7楼-- · 2019-01-08 17:12

I think that the best answer here is the function proposed by @JaredPar, but if you like one-liners as I do I'd like to propose following Any one-liner:

# Any item is greater than 5
$result = $arr | %{ $match = $false }{ $match = $match -or $_ -gt 5 }{ $match }

%{ $match = $false }{ $match = $match -or YOUR_CONDITION }{ $match } checks that at least one item match condition.

One note - usually the Any operation evaluates the array until it finds the first item matching the condition. But this code evaluates all items.

Just to mention, you can easily adjust it to become All one-liner:

# All items are greater than zero
$result = $arr | %{ $match = $false }{ $match = $match -and $_ -gt 0 }{ $match }

%{ $match = $false }{ $match = $match -and YOUR_CONDITION }{ $match } checks that all items match condition.

Notice, that to check Any you need -or and to check All you need -and.

查看更多
登录 后发表回答