Trying to condense conditional with three possibilities

Asked

Viewed 714 times

7

The problem is to present a result flexing to the plural if necessary, or "no":

Let ni>=0 (number of items):

switch(true){
        case  $ni==0:
            $html = ' (nenhum)';
            break;
        case $ni==1:
            $html = ' (1 item)';
            break;
        case $ni>1:
            $html = ' ('.$ni.' itens)';
            break;
    }

This is working, now with ifs, a little smaller:

if($ni > 1){
        $html = ' ('.$ni.' itens)';
    } else if($ni == 1){
        $html = ' (1 item)';
    } else {
        $html = ' (nenhum)';
    }

It works too, but now the condensed form I tried to make:

$html = ($ni > 1)? ' ('.$ni.' itens)' : ($ni==1)? ' (1 item)' : ' (nenhum)' ;

This does not work, it responds "none" correctly, "1 item" correctly, but for ni>1 always responds "1 item".

The idea is to condense an if, Else if, Else into a line, but not if it is possible, since the logic seems correct. There is another condensed form?

  • Just one observation, I think the correct term would be "ternary operator" rather than "condensed form".

4 answers

11


Parentheses left on the nested probation:

$html = ($ni > 1) ? ' ('.$ni.' itens)' : (($ni==1) ? ' (1 item)' : ' (nenhum)');
//                                       ^                                    ^

Without it, the PHP prioritizes the first sequence of ?: who finds, and the code is understood this way:

$html = (($ni > 1) ? ' ('.$ni.' itens)' : ($ni==1)) ? ' (1 item)' : ' (nenhum)';

If $ni for 2, That’s how it ends up interpreted:

$html = ((2 > 1) ? ' (2 itens)' : 2==1)) ? ' (1 item)' : ' (nenhum)';

Therefore:

$html = (true ? ' (2 itens)' : false)) ? ' (1 item)' : ' (nenhum)';

And then:

$html = ' (2 itens)' ? ' (1 item)' : ' (nenhum)';

That is to say:

$html = true ? ' (1 item)' : ' (nenhum)';

And finally:

$html = ' (1 item)';

Anyway, I find it barely readable1. It’s a matter of opinion, but of the three options you’ve tested, I prefer the ifs.

(1) In the link I’m talking about Javascript, but this operator works the same in both languages (and in other languages)

  • It worked beauty! In fact, ifs are nicer, too, I think, but there’s another question: I deal with multiple languages and sometimes multiple definitions are not suitable. Also, if you need to use many times, it will be more practical to copy and paste a single!

  • 2

    I agree. I also prefer the ifin this case. The switch(true) I’ve never seen anyone wear it, and the ternary, when they’re nested, is barely legible.

  • I think you could improve the text of that link because in recent versions (relatively speaking) ?: is a short variant of the ternary operator (which I never understood how it works >.<) and can cause confusion.

5

Only an implementation alternative if using PHP 5.5:

$html = [' (nenhum)', ' (1 item)', ' ('.$ni.' itens)'][($ni > 1) ? 2 : $ni];

I find it simpler this way. I don’t like double conditional on ternary operator.

It is possible to do the same before version 5.5 but it is not as simple (at least compared to the version of the double ternary):

$textos = [' (nenhum)', ' (1 item)', ' ('.$ni.' itens)'];
$html = $textos[($ni > 1) ? 2 : $ni];

This still requires PHP 5.4. For earlier versions:

$textos = array(' (nenhum)', ' (1 item)', ' ('.$ni.' itens)');
$html = $textos[($ni > 1) ? 2 : $ni];

With if for those who prefer (each time getting less advantageous):

$textos = array(' (nenhum)', ' (1 item)', ' ('.$ni.' itens)');
if($ni > 1) {
    $html = $textos[2];
} else {
    $html = $textos[$ni];
}

Finally enjoying other responses posted as I would in this situation:

function pluralization( $numItems = 0, $texts) {
    if ($texts == NULL) {
        $texts = array("(nenhum)", "(1 item)", "($numItems itens)");
    }
    return $texts[min($numItems, 2)];
}

echo pluralization(0);
echo pluralization(0);
echo pluralization(1);
echo pluralization(2);
echo pluralization(3);
$elementos = 4; // podia usar o letral direto mas no uso real vai fazer mais sentido com uma variável
echo pluralization($elementos, ["nada", "um elemento", "$elementos elementos"]);

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

  • In this case I don’t think it’s the same since you only have one condition. I would particularly do so but I find it perfectly valid that other people prefer the use of if and I would make use of it too if my team preferred it that way. But now I’ve made a version with if.

4

Version without if:

I would normally do this in PHP 5.4+ (which allows direct access to arrays):

$ni = 6;
echo array('nenhum', 'um ítem', "$ni ítens")[min($ni,2)];

5.5 (I do not remember if 5.4 already allows)

echo ['nenhum', 'um ítem', "$ni ítens"][min($ni,2)];

In PHP 5.3- it’s not as elegant as it needs a variable, but it looks good in a function:

echo humano( 0 )."\n";
echo humano( 1 )."\n";
echo humano( 2 )."\n";
echo humano( 3 )."\n";
echo humano( 4 )."\n";

function humano($ni) {
   $out = array( 'nenhum', 'um ítem', "$ni ítens");
   return $out[min($ni,2)];
}

See working on IDEONE.

3

All answers deal perfectly with the problem, including some solutions in the question.

I am going to leave a suggestion that is very much in line with what has already been pointed out in some comments and answers that is to leave the code reduced, yes, but with reading so that in the future it is quick to analyze the same:

Example

$html = ' (nenhum)';

if ($ni >= 1) {

    $html = ($ni == 1) ? ' (1 item)' : ' ('.$ni.' itens)';
}

My model has a default value. This amount will be subscribed only if necessary. The subscription takes into account the plural based on the number of items.

See example for $ni=0, $ni=1 and $ni=2 in the Ideone.

Example 02 (for those who are allergic to parentheses ;))

$html = ' (nenhum)';

if ($ni >= 1)
    $html = ($ni == 1) ? ' (1 item)' : ' ('.$ni.' itens)';

Reuse code:

This type of checks tends to be used several times, which leads us to reduce their code. A simplicist approach to code reduction without the same reading loss is the creation of a function:

Function

/**
 * Total itens
 *
 * Com base no número recebido, devolve uma indicação
 * humanamente legível sobre o total de itens.
 *
 * @param integer $i Número a analisar.
 * return $string $html HTML pronto a utilizar.
 */
function totalItens ($i=0) {

  $html = ' (nenhum)';

  if ($i >= 1) {

    $html = ($i == 1) ? ' (1 item)' : ' ('.$i.' itens)';
  }

  return $html;
}

Example of use

echo totalItens(3);  // saída: (3 itens)

See example of function in Ideone.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.