Compare range of values

Asked

Viewed 123 times

5

The code below compares a value and according to this value generates a percentage and works. But I would like a more practical way, whether function or other structure, because these ranges of values can be very large.

How to simplify the structure below?

    if($valor>0 and $valor<=5000){
        $percentual = 0.41;
    }elseif($valor>5000 and $valor<=10000){
        $percentual = 0.42;
    }elseif($valor>10000 and $valor<=15000){
        $percentual = 0.43;
    }elseif($valor>15000 and $valor<=20000){
        $percentual = 0.44;
    }elseif($valor>20000 and $valor<=25000){
        $percentual = 0.5;
    }elseif($valor>25000 and $valor<=30000){
        $percentual = 0.57;
    }elseif($valor>30000 and $valor<=35000){
        $percentual = 0.6;
    }elseif($valor>35000 and $valor<=40000){
        $percentual = 0.8;
    }elseif($valor>40000 and $valor<=45000){
        $percentual = 0.84;
    }elseif($valor>45000 and $valor<=50000){
        $percentual = 0.87;
    }elseif($valor>50000 and $valor<=55000){
        $percentual = 0.92;
    }elseif($valor>55000 and $valor<=60000){
        $percentual = 1.0;
    }elseif($valor>60000 and $valor<=65000){
        $percentual = 1.02;
    }elseif($valor>65000 and $valor<=70000){
        $percentual = 1.23;
    }elseif($valor>70000 and $valor<=75000){
        $percentual = 1.25;
    }elseif($valor>75000 and $valor<=80000){
        $percentual = 2;
    }else{
        $percentual = 5;
    }

The "step" between a track and another will always be fixed. In the case of the example above 5000. But the limit may vary, in the above example was 0 to 80000.

3 answers

6

As the tracks are regular it is very easy because you can use only the math and a array with the values.

I didn’t put all the values (without them I would fail in the tracks I didn’t put), but I can understand that. has only one exception when it reaches the limit value. I have not treated values outside the range as negative because the original does not deal with.

$valor = 10000;
$percentuais = Array(0.41, 0.42, 0.43, 0.44, 0.5, 0.6);
$percentual = $valor > 80000 ? 5 : $percentuais[($valor - 1) / 5000];
echo $percentual;

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

3

You can create a array with all possible values and go through the same and make only one if within the foreach, I believe that it is better to give maintenance and also to understand the code.

$data = [
    [
        'start' => 0,
        'end' => 5000,
        'percentage' => 0.41,
    ],
    [
        'start' => 5000,
        'end' => 10000,
        'percentage' => 0.42,
    ],
    [
        'start' => 10000,
        'end' => 15000,
        'percentage' => 0.43,
    ]
];


$valor = 11000;
$percentage = 0;

if ($valor > end($data)['end']) {
    $percentage = 5;    
} else {
    foreach ($data as $value) {
        if ($valor > $value['start'] && $valor <= $value['end']) {
            $percentage = $value['percentage'];     
            break;
        }
    }   
}

echo $percentage;

// Valor impresso: 0.43
  • 2

    As you define the need to have a "roof" of track, and have no treatment for "open ceiling", your code will not work for the case 80001.

  • Yes you’re right but then just put one else and define $percentage equal to 5.

2


Maniero’s response is very practical, but for maintenance it is confusing because if you want to change the percentage of a track is confused to know which item of the array to change.

For example, if you want to change the percentage of the range $valor>50000 e $valor<=55000 you will not know which item (index) of the array to change, even more if there are many. You will need to know which track index and count with your fingers until you reach the right index, still at risk of changing the wrong index.

For example, if you have values from 0 to 200,000 (you said this could vary), you will have an array of 40 items (the values below are illustrative):

$percentuais = Array(
0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1,
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2,
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3,
3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4,
);

Say you want to change the range of >70000 e <=75000, Which item of the above array will you change? It’s hard to know.

The idea of Kayo’s answer is interesting in terms of maintenance, but I would do it in a simpler way, using arrays with only two items:

$faixas = [
   [5000, .41],
   [10000, .42],
   [15000, .43],
   [20000, .44],
   [25000, .5],
   [30000, .57]
];

In the arrays I put in the first item the maximum value and in the second item the percentage.

Making a foreach you can know which of these arrays has a value where the variable $valor fits the same criteria as its original code:

foreach($faixas as $v){
   if($valor <= $v[0]){
      $porcentagem = $v[1];
      break;
   }
}

If $valor, for example, for 2000, the first array (where the index [0] is 5000) already satisfies and the loop is canceled with break, assigning to the variable $porcentagem the value of the index [1] of that array. If $valor for 6000, will pass straight from the first array and stop at the second, and so on.

I find this way easier to maintain. For example, if you want feathers change the percentage of the range going from 15001 to 20000, you will change only the array:

[20000, .44]

In the case of $valor be less than or equal to 0 or greater than the value of the last track, you make a if assigning the value 5 to the variable $porcentagem, otherwise enters the else and does the foreach. Complete code:

$valor = 5000;

$faixas = [
   [5000, .41],
   [10000, .42],
   [15000, .43],
   [20000, .44],
   [25000, .5],
   [30000, .57]
];

if($valor > end($faixas)[0] || $valor < 1){
   $porcentagem = 5;
}else{
   foreach($faixas as $v){
      if($valor <= $v[0]){
         $porcentagem = $v[1];
         break;
      }
   }
}

echo $porcentagem; // 0.41

See working on IDEONE.

Just one observation: your code does not show, but in case you are checking before if $valor is greater than 0 (which I think likely), do not need to put the condition || $valor < 1 in the if. Just leave it at that:

if($valor > end($faixas)[0]){
  • 1

    Really for maintenance is clearer. Thank you

  • Great answer, I agree that for maintenance will be much simpler to understand, especially if the person who is providing maintenance is not the same who made the code.

  • This way the tracks could be "irregular" ? $valor>0 and $valor<=2365and $valor>2365 and $valor<=3122 ?

  • @Pedroaugusto Absolutely. As long as each array is in the ascending order as I put in the answer, there is no problem.

Browser other questions tagged

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