2010-01-19 61 views
4

我写这个(工作):Powershell的相当于F#Seq.forall

function ForAll { 
    BEGIN { 
     $allTrue = $true 
    } 
    PROCESS { 
     if ($_ -lt 1) { $allTrue = $false } 
    } 
    END { 
     $allTrue 
    } 
} 

$aList = (0..4) 
$bList = (1..4) 

$aList | ForAll # returns false 
$bList | ForAll # returns true 

但我想要做的就是更换($ _ -lt 1)用函数调用类似$我传入ForAll函数的谓词。我似乎无法得到这个工作。有任何想法吗?

回答

3

使用[scriptblock],这比在这里使用函数要容易得多。这就是为什么scriptblocks被发明的任务。

function ForAll([scriptblock]$predicate) { 

    BEGIN { 
     $allTrue = $true 
    } 
    PROCESS { 
     if (!(& $predicate $_)) { $allTrue = $false } 
    } 
    END { 
     $allTrue 
    } 
} 

$aList = (0..4) 
$bList = (1..4) 

$aList | ForAll {$args[0] -le -10 } # returns false 
$bList | ForAll {$args[0] -le 10 } # returns true 

$ args [0]表示传递给scriptblock的第一个参数 - 在本例中为$ _。

+0

Stej,我在此将[脚本块]如果$ _被取代的$ args [实际上是不需要的通知0]。有一天晚上,我试图让这个工作起来,让我感到很困惑。最后,我得到的最短版本只是对你的一个小小的改变。 功能的ForAll($谓语){ ...} $ ALIST =(0..4) $ bList =(1..4) $ ALIST | ForAll {$ _ -gt 0}#返回false $ bList | ForAll {$ _ -gt 0}#返回true $ bList | ForAll {$ _ -gt 0 - 和$ _ -lt 5}#返回true – 2010-01-23 04:50:09

+0

是的,这是绝对真实的。您可以使用自动变量 - 它看起来与foreach-object cmdlet相同。但是,我在$ _中遇到了一些更复杂的脚本问题,所以我不愿意使用$ _。 – stej 2010-01-24 20:59:57

3

如果你在PowerShell 2.0中,你可以使用PARAM用脚本块声明参数,如:

function ForAll { 
    param(
     [Parameter(Position=0,Mandatory=$true)] 
     [scriptblock] 
     $Expression, 

     [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true)] 
     [psobject] 
     $InputObject 
    ) 

    Begin { $allTrue = $true } 

    Process { 
     foreach ($obj in $InputObject) { 
      if (!(&$Expression $obj)) { $allTrue = $false } 
     } 
    } 

    End { $allTrue } 
} 

$aList = (0..4) 
$bList = (1..4) 

ForAll {param($val) $val -gt 0} (0..4) # returns false 

$aList | ForAll {param($val) $val -gt 0} # returns false 
$bList | ForAll {param($val) $val -gt 0} # returns true 
$aList | ForAll {param($val) $val -ge 0 -and $val -le 4} # returns true 
+1

我一直想看到可以从管道和参数中正确处理参数。我会记住foreach的诀窍。有什么理由不去管它吗? $ InputObject | %{if(!(&$ Expression $ _)){$ allTrue = $ false}} } – stej 2010-01-19 20:09:21

+0

不会 - 那也行得通。当我编写函数时,我倾向于回到我的C#(非流水线)循环方式。 :-)小管道很容易阅读,但是当他们一行接一行时,我发现显式循环更容易阅读,当我回到脚本。 – 2010-01-19 20:25:46

+0

我不明白,你为什么需要这个foreach?我认为过程是为了从管道中获取个体价值? $ InputObject绑定到进程内的单个项目吗? (因为属性)如果这就是为什么使用开始,处理,结束的情况? – Jake 2011-05-13 16:37:37

0

为了有效处理,我们会使用,而不是一个功能的过滤器,我们将“破发”的我们发现了虚假元素。这也将停止所有上游过程太:

filter ForAll([scriptblock] $predicate) { 
    PROCESS { 
     if (@($_ | Where-Object $predicate).Length -eq 0) { 
      $false; 
      break; 
     } 
    } 
    END { 
     $true; 
    } 
} 

惯用使用它:

(0..4) | ForAll { $_ -gt 0 }  # returns false 
(1..4) | ForAll { $_ -gt 0 }  # returns true