2010-01-19 107 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