Тернарный оператор в PowerShell

Из того, что я знаю, PowerShell, похоже, не имеет встроенного выражения для так называемого тернарного оператора.

Например, на языке C, который поддерживает тернарный оператор, я мог бы написать что-то вроде:

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

Если это действительно не существует в PowerShell, что было бы лучшим способом (то есть легко читать и поддерживать) для достижения того же результата?

Ответ 1

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

Все остальное является случайной сложностью и, следовательно, его следует избегать.

Для использования в выражении или в качестве выражения, а не просто для присвоения, оберните его в $(), таким образом:

write-host  $(If ($condition) {"true"} Else {"false"}) 

Ответ 2

Самая близкая конструкция PowerShell, которую я смог придумать для эмуляции:

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

Ответ 3

В этом сообщении блога 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})

Ответ 4

Я тоже искал лучшего ответа, и хотя решение в должности Эдварда "нормально", я придумал гораздо более естественное решение в этом сообщении в блоге

Короткий и сладкий:

# ---------------------------------------------------------------------------
# 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 Invoke-Assignment."

Что позволяет легко делать такие вещи (больше примеров в блоге):

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

Ответ 5

Попробуйте в качестве альтернативы оператор PowerShell switch, особенно для присваивания переменных - несколько строк, но удобочитаемых.

Пример,

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

Ответ 6

Так как при присвоении значения обычно используется тернарный оператор, он должен возвращать значение. Это способ работы:

[email protected]("value if false","value if true")[[byte](condition)]

Глупо, но работает. Также эту конструкцию можно использовать для быстрого превращения int в другое значение, просто добавьте элементы массива и укажите выражение, которое возвращает 0-основанные неотрицательные значения.

Ответ 7

Недавно я улучшил (откройте PullRequest) троичные условные операторы и операторы с нулевым слиянием в библиотеке PoweShell Pscx
Просьба взглянуть на мое решение.


Моя ветка тем github: UtilityModule_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"

Usage

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

<variable_expression> |?? <alternate_expression>

В качестве выражения вы можете передать:
          $ null, литерал, переменная, "внешнее" выражение ($ b -eq 4) или блок сценария {$ b -eq 4}

Если переменная в выражении переменной равна $ null или не существует, альтернативное выражение оценивается как выходной.

Ответ 8

Поскольку я уже использовал это много раз и не увидел его здесь, я добавлю свою часть:

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

самый уродливый из всех!

своего рода источник

Ответ 10

Здесь альтернативный подход к пользовательским функциям:

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'

Различия Разъяснения

  • Почему это 3 вопросительные знаки вместо 1?
    • Символ ? уже является псевдонимом для Where-Object.
    • ?? используется в других языках в качестве оператора нулевой коалесценции, и я хотел избежать путаницы.
  • Зачем нам нужна труба перед командой?
    • Поскольку я использую конвейер для оценки этого, нам все еще нужен этот символ, чтобы передать условие в нашу функцию
  • Что произойдет, если я пройду массив?
    • Мы получаем результат для каждого значения; т.е. -2..2 |??? 'match' : 'nomatch' дает: match, match, nomatch, match, match (т.е. поскольку любое ненулевое int вычисляет true, а нуль - false).
    • Если вы этого не хотите, преобразуйте массив в bool; ([bool](-2..2)) |??? 'match' : 'nomatch' (или просто: [bool](-2..2) |??? 'match' : 'nomatch')