web-dev-qa-db-ja.com

PowerShellの三項演算子

私が知っていることから、PowerShellはいわゆる 三項演算子 のための組み込み式を持っていないようです。

たとえば、三項演算子をサポートするC言語では、次のように書くことができます。

<condition> ? <condition-is-true> : <condition-is-false>;

それがPowerShellに実際には存在しない場合、同じ結果を達成するための最善の方法(つまり、読みやすく保守しやすい)は何でしょうか。

156
mguassa
$result = If ($condition) {"true"} Else {"false"}

他のすべては付随的な複雑さであり、したがって避けるべきです。

代入だけではなく式で、または式として使用するには、$()で囲みます。

write-Host  $(If ($condition) {"true"} Else {"false"}) 
234
fbehrens

これをエミュレートするために私が思いつくことができた最も近いPowerShellの構成は、次のとおりです。

@({'condition is false'},{'condition is true'})[$condition]
46
mjolinor

これにより PowerShellブログ投稿?:演算子を定義するためのエイリアスを作成することができます。

set-alias ?: Invoke-Ternary -Option AllScope -Description "PSCX filter alias"
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse) 
{
   if (&$decider) { 
      &$ifTrue
   } else { 
      &$ifFalse 
   }
}

このように使用してください。

$total = ($quantity * $price ) * (?:  {$quantity -le 10} {.9} {.75})
24
Edward Brey

私も、より良い答えを探しました。そして、Edwardの投稿の解決策は "ok"ですが、私ははるかに自然な解決策を思いつきました このブログ投稿の解決策

短くて甘い:

# ---------------------------------------------------------------------------
# Name:   Invoke-Assignment
# Alias:  =
# Author: Garrett Serack (@FearTheCowboy)
# Desc:   Enables expressions like the C# operators: 
#         Ternary: 
#             <condition> ? <trueresult> : <falseresult> 
#             e.g. 
#                status = (age > 50) ? "old" : "young";
#         Null-Coalescing 
#             <value> ?? <value-if-value-is-null>
#             e.g.
#                name = GetName() ?? "No Name";
#             
# Ternary Usage:  
#         $status == ($age > 50) ? "old" : "young"
#
# Null Coalescing Usage:
#         $name = (get-name) ? "No Name" 
# ---------------------------------------------------------------------------

# returns the evaluated value of the parameter passed in, 
# executing it, if it is a scriptblock   
function eval($item) {
    if( $item -ne $null ) {
        if( $item -is "ScriptBlock" ) {
            return & $item
        }
        return $item
    }
    return $null
}

# an extended assignment function; implements logic for Ternarys and Null-Coalescing expressions
function Invoke-Assignment {
    if( $args ) {
        # ternary
        if ($p = [array]::IndexOf($args,'?' )+1) {
            if (eval($args[0])) {
                return eval($args[$p])
            } 
            return eval($args[([array]::IndexOf($args,':',$p))+1]) 
        }

        # null-coalescing
        if ($p = ([array]::IndexOf($args,'??',$p)+1)) {
            if ($result = eval($args[0])) {
                return $result
            } 
            return eval($args[$p])
        } 

        # neither ternary or null-coalescing, just a value  
        return eval($args[0])
    }
    return $null
}

# alias the function to the equals sign (which doesn't impede the normal use of = )
set-alias = Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment."

これにより、次のようなことを簡単に行うことができます(ブログ投稿の他の例)。

$message == ($age > 50) ? "Old Man" :"Young Dude" 
20
Garrett Serack

PowerShellのswitchステートメントを代替変数として試してみてください。特に変数の代入のために。

例、

$WinVer = switch ( Test-Path $Env:windir\SysWOW64 ) {
  $true    { "64-bit" }
  $false   { "32-bit" }
}
"This version of Windows is $WinVer"
9
nudl

通常、値を割り当てるときには3項演算子が使用されるため、値を返す必要があります。これはうまくいく方法です:

$var=@("value if false","value if true")[[byte](condition)]

愚かな、しかし働いている。また、この構造は、intを別の値に素早く変換し、配列要素を追加し、0から始まる負以外の値を返す式を指定するためにも使用できます。

9
Vesper

私はすでにこれを何度も使っていて、ここにリストされているのを見なかったので、私は私の作品を追加します:

$var = @{$true="this is true";$false="this is false"}[1 -eq 1]

何よりも醜い!

ちょっとソース

4
sodawillow

私は最近PoweShellライブラリ 'Pscx'の三項条件付き演算子とnull合体演算子を改良しました(open PullRequest)。
Plsは私の解決策を探しています。


私のgithubトピックブランチ:tilityModule_Invoke-Operators

関数:

Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe

エイリアス

Set-Alias :?:   Pscx\Invoke-Ternary                     -Description "PSCX alias"
Set-Alias ?:    Pscx\Invoke-TernaryAsPipe               -Description "PSCX alias"
Set-Alias :??   Pscx\Invoke-NullCoalescing              -Description "PSCX alias"
Set-Alias ??    Pscx\Invoke-NullCoalescingAsPipe        -Description "PSCX alias"

使用法

<condition_expression> |?: <true_expression> <false_expression>

<variable_expression> |?? <alternate_expression>

式として渡すことができます:
$ null、リテラル、変数、 '外部'式($ b -eq 4)、またはスクリプトブロック{$ b -eq 4}

変数式中の変数が$ nullまたは存在しない場合、代替式は出力として評価されます。

3
andiDo

これが代替のカスタム関数アプローチです。

function Test-TernaryOperatorCondition {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, Mandatory = $true)]
        [bool]$ConditionResult
        ,
        [Parameter(Mandatory = $true, Position = 0)]
        [PSObject]$ValueIfTrue
        ,
        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateSet(':')]
        [char]$Colon
        ,
        [Parameter(Mandatory = $true, Position = 2)]
        [PSObject]$ValueIfFalse
    )
    process {
        if ($ConditionResult) {
            $ValueIfTrue
        }
        else {
            $ValueIfFalse
        }
    }
}
set-alias -Name '???' -Value 'Test-TernaryOperatorCondition'

1 -eq 1 |??? 'match' : 'nomatch'
1 -eq 2 |??? 'match' : 'nomatch'

違いの説明

  • 1ではなく3つの疑問符があるのはなぜですか?
    • ?文字は既にWhere-Objectの別名です。
    • ??は他の言語ではnull合体演算子として使われています、そして私は混乱を避けたいと思いました。
  • コマンドの前にパイプが必要なのはなぜですか?
    • 私はこれを評価するためにパイプラインを利用しているので、私たちはまだ条件を私たちの関数に渡すためにこの文字が必要です
  • 配列を渡すとどうなりますか。
    • 値ごとに結果が得られます。すなわち、-2..2 |??? 'match' : 'nomatch'は、match, match, nomatch, match, matchを与える(すなわち、ゼロでない整数はtrueと評価されるので、ゼロはfalseと評価されるため)。
    • そうしたくない場合は、配列をブール値に変換してください。 ([bool](-2..2)) |??? 'match' : 'nomatch'(または単に[bool](-2..2) |??? 'match' : 'nomatch'
0
JohnLBevan