Trying to condense conditional with three possibilities

7

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

Let 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. Is there another condensed form?

    
asked by anonymous 03.12.2014 / 01:25

4 answers

11

Parentheses are missing in nested conditional:

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

Without this, PHP prioritizes the first string of ?: found , and the code is understood like this:

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

If $ni is 2 , this ends up being interpreted like this:

$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:

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

And finally:

$html = ' (1 item)';

Either way, I find this unreadable 1 . It's a matter of opinion, but of the 3 options you tested, I'd prefer the% s of% s.

    
03.12.2014 / 01:39
5

Only an implementation alternative if you are using PHP 5.5 :

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

I find it simpler that way. I do not like conditional double in ternary operator.

You can do the same before version 5.5 but it is not so simple (at least comparing with 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 previous versions:

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

With if for those who prefer (becoming less and less advantageous):

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

Finally taking advantage of other answers 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"]);

See running on ideone . And in Coding Ground . Also put it in GitHub for future reference .

    
03.12.2014 / 12:46
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 (can 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 looks good on 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 at IDEONE .

    
03.12.2014 / 13:18
3

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

I'll leave a suggestion that goes well with the one already mentioned in some comments and answers that goes by leaving the code reduced yes, but with reading so that in the future it is quick to analyze it:

Example

$html = ' (nenhum)';

if ($ni >= 1) {

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

My template has a default value. This value will be subscribed only if necessary. The subscription of the same takes into account the plural based on the quantity 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 your code. A simplicist approach to code reduction without losing it passes through 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;
}

Usage example

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

See example of the function in Ideone .

    
03.12.2014 / 14:33