Rewrite a PHP function with arrays instead - php

Is there any way I could rewrite this function with an array instead of all these if statements? Could i maybe use some for loop together with an array? How would that look like? Any suggestions of simpler code?
Here is my php function:
function to_next_level($point) {
/*
**********************************************************************
*
* This function check how much points user has achievents and how much procent it is until next level
*
**********************************************************************
*/
$firstlevel = "3000";
$secondlevel = "7000";
$thirdlevel = "15000";
$forthlevel = "28000";
$fifthlevel = "45000";
$sixthlevel = "80000";
if($point <= $firstlevel) {
$total = ($point/$firstlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $secondlevel) {
$total = ($point/$secondlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $thirdlevel) {
$total = ($point/$thirdlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $forthlevel) {
$total = ($point/$forthlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $fifthlevel) {
$total = ($point/$fifthlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $sixthlevel) {
$total = ($point/$sixthlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
}
}

Try this:
function to_next_level($point) {
/*
**********************************************************************
*
* This function check how much points user has achievents and how much procent it is until next level
*
**********************************************************************
*/
$levelArray = array(3000, 7000, 15000, 28000, 45000, 80000);
foreach ($levelArray as $level)
{
if ($point <= $level) {
$total = ($point/$level) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
}
}
}

Start using OOP programming style. This is the perfect opportunity since it is a task without much complexity. Create a class that acts as central authority. That class can receive more methods over time. That way your code stays easy to maintain since all those functions are kept inside a class.
<?php
class levelAuthority
{
public static $thresholds = [ 3000, 7000, 15000, 28000, 45000, 80000 ];
public static function getDistanceToNextlevel($points)
{
foreach (self::$thresholds as $threshold) {
if ($points <= $threshold) {
$total = ($points/$threshold) * 100;
$remaining = round($total);
return $remaining;
}
}
}
}
// in the calling scope:
$points = 5000;
echo levelAuthority::getDistanceToNextlevel($points);

lots of answers to this!!
here is mine using a while loop - single exit point outside the loop:
function to_next_level($point) {
/*
**********************************************************************
*
* This function check how much points user has achievements and how much percent it is until next level
*
**********************************************************************
*/
$arr_level = array(3000,15000,28000,45000,80000);
$remaining = false;
while (!$remaining and list($key,$level) = each($arr_level)) {
if ($point <= $level) {
$total = ($point/$level) * 100;
$remaining = round($total);
}
}
// will return false if $point is greater than highest value in $arr_level
return $remaining;
}

You could write an additional function, that does the calculations and trigger it from the if/else if/else blocks.
function calculate_remaining($points, $level) {
$total = ($point/$level) * 100;
$remaining = round($total);
return $remaining;
}
You'd trigger this like:
if($point <= $firstlevel) {
return $calculate_remaining($point, $firstlevel);
} elseif ($point <= $secondlevel) {
return $calculate_remaining($point, $secondlevel);
} etc.

What about something like this?
function to_next_level($point)
{
$levels = array(
3000,
7000,
15000,
28000,
45000,
80000
);
foreach ($levels as $level)
{
if ($point <= $level)
{
$total = ($point / $level) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
}
}
}
The point levels are in order in the array, so [0] is $firstlevel, and so on. You simply iterate through the array and return whenever we reach the condition where $point is <= to the the $level.
Also, since $levels is static, it can be defined outside of the function.

simple:
<?php
$point = 100;
$remaining = 0;
$data = [
'firstlevel' => 3000,
'secondlevel' => 7000,
'thirdlevel' => 15000,
'forthlevel' => 28000,
'fifthlevel' => 45000,
'sixthlevel' => 80000
];
foreach($data as $item)
{
if($point <= $item)
{
$remaining = round(($point / $item ) * 100); //or return val
}
}

How about putting your variable into array and loop it?
function to_next_level($point) {
$data[0] = "3000";
$data[1] = "7000";
$data[2] = "15000";
$data[3] = "28000";
$data[4] = "45000";
$data[5] = "80000";
foreach ($data as $key => $value) {
if($point <= $value) {
$total = ($point/$value) * 100;
$remaining = round($total);
return $remaining;
}
}
}
I haven't try it. But it might work for you.

Related

Laravel Eloquent How to get 1st and 3rd quartile on php?

I'm trying to find outliers using the 1st and 3rd quartile. This is what I have currently:
$data = Data::select('created_at', 'value')
->get();
$median = collect($data)->median("value");
You can create a private function like this:
function Quartile($Array, $Quartile) {
sort($Array);
$pos = (count($Array) - 1) * $Quartile;
$base = floor($pos);
$rest = $pos - $base;
if( isset($Array[$base+1]) ) {
return $Array[$base] + $rest * ($Array[$base+1] - $Array[$base]);
} else {
return $Array[$base];
}
}
function Average($Array) {
return array_sum($Array) / count($Array);
}
function StdDev($Array) {
if( count($Array) < 2 ) {
return;
}
$avg = Average($Array);
$sum = 0;
foreach($Array as $value) {
$sum += pow($value - $avg, 2);
}
return sqrt((1 / (count($Array) - 1)) * $sum);
}
Then, you can call the Quartile() method depends on which quartile you want, if you want the first quartile, then put 0.25 for the as $Quartile's parameter value, for the third quartile, its 0.75.
Source answer

Basic perceptron for AND gate in PHP, am I doing it right? Weird results

I'd like to learn about neural nets starting with the very basic perceptron algorithm. So I've implemented one in PHP and I'm getting weird results after training it. All the 4 possible input combinations return either wrong or correct results (more often the wrong ones).
1) Is there something wrong with my implementation or the results I'm getting are normal?
2) Can this kind of implementation work with more than 2 inputs?
3) What would be the next (easiest) step in learning neural nets after this? Maybe adding more neurons, changing the activation function, or ...?
P.S. I'm pretty bad at math and don't necessarily understand the math behind perceptron 100%, at least not the training part.
Perceptron Class
<?php
namespace Perceptron;
class Perceptron
{
// Number of inputs
protected $n;
protected $weights = [];
protected $bias;
public function __construct(int $n)
{
$this->n = $n;
// Generate random weights for each input
for ($i = 0; $i < $n; $i++) {
$w = mt_rand(-100, 100) / 100;
array_push($this->weights, $w);
}
// Generate a random bias
$this->bias = mt_rand(-100, 100) / 100;
}
public function sum(array $inputs)
{
$sum = 0;
for ($i = 0; $i < $this->n; $i++) {
$sum += ($inputs[$i] * $this->weights[$i]);
}
return $sum + $this->bias;
}
public function activationFunction(float $sum)
{
return $sum < 0.0 ? 0 : 1;
}
public function predict(array $inputs)
{
$sum = $this->sum($inputs);
return $this->activationFunction($sum);
}
public function train(array $trainingSet, float $learningRate)
{
foreach ($trainingSet as $row) {
$inputs = array_slice($row, 0, $this->n);
$correctOutput = $row[$this->n];
$output = $this->predict($inputs);
$error = $correctOutput - $output;
// Adjusting the weights
$this->weights[0] = $this->weights[0] + ($learningRate * $error);
for ($i = 0; $i < $this->n - 1; $i++) {
$this->weights[$i + 1] =
$this->weights[$i] + ($learningRate * $inputs[$i] * $error);
}
}
// Adjusting the bias
$this->bias += ($learningRate * $error);
}
}
Main File
<?php
require_once 'vendor/autoload.php';
use Perceptron\Perceptron;
// Create a new perceptron with 2 inputs
$perceptron = new Perceptron(2);
// Test the perceptron
echo "Before training:\n";
$output = $perceptron->predict([0, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([0, 1]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 1]);
echo "{$output} - " . ($output == 1 ? 'correct' : 'nope') . "\n";
// Train the perceptron
$trainingSet = [
// The 3rd column is the correct output
[0, 0, 0],
[0, 1, 0],
[1, 0, 0],
[1, 1, 1],
];
for ($i = 0; $i < 1000; $i++) {
$perceptron->train($trainingSet, 0.1);
}
// Test the perceptron again - now the results should be correct
echo "\nAfter training:\n";
$output = $perceptron->predict([0, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([0, 1]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 1]);
echo "{$output} - " . ($output == 1 ? 'correct' : 'nope') . "\n";
I must thank you for posting this question, I have wanted a chance to dive a little deeper into neural networks. Anyway, down to business. After tinkering around and verbose logging what all is happening, it ended up only requiring 1 character change to work as intended:
public function sum(array $inputs)
{
...
//instead of multiplying the input by the weight, we should be adding the weight
$sum += ($inputs[$i] + $this->weights[$i]);
...
}
With that change, 1000 iterations of training ends up being overkill.
One bit of the code was confusing, different setting of weights:
public function train(array $trainingSet, float $learningRate)
{
foreach ($trainingSet as $row) {
...
$this->weights[0] = $this->weights[0] + ($learningRate * $error);
for ($i = 0; $i < $this->n - 1; $i++) {
$this->weights[$i + 1] =
$this->weights[$i] + ($learningRate * $inputs[$i] * $error);
}
}
I don't necessarily understand why you chose to do it this way. My unexperienced eye would think that the following would work as well.
for ($i = 0; $i < $this->n; $i++) {
$this->weight[$i] += $learningRate * $error;
}
Found my silly mistake, I wasn't adjusting the bias for each row of a training set as I accidentally put it outside the foreach loop. This is what the train() method should look like:
public function train(array $trainingSet, float $learningRate)
{
foreach ($trainingSet as $row) {
$inputs = array_slice($row, 0, $this->n);
$correctOutput = $row[$this->n];
$output = $this->predict($inputs);
$error = $correctOutput - $output;
// Adjusting the weights
for ($i = 0; $i < $this->n; $i++) {
$this->weights[$i] += ($learningRate * $inputs[$i] * $error);
}
// Adjusting the bias
$this->bias += ($learningRate * $error);
}
}
Now I get the correct results after training each time I run the script. Just 100 epochs of training is enough.

How can I have a correct decimal format with a PHP namespace function?

I am working on my program to include name spaces, and I have been having some issues with decimal points. The number I am trying to achieve is $11,698.58 for a Future Value application that I am working on. But the application is printing out this number: 11698.5856. Did i do a little mess up on the code? I just need another pair of eyes to help me out on this one. Thanks!
functions.php
<?php
namespace fuller\math{
function future_value($investment, $years, $interest_rate, $future_value_f, $compoundMonthly = FALSE){
// calculate the future value
$future_value = $investment;
$future_value_f = '$' . number_format($future_value, 2);
for ($i = 1; $i <= $years; $i++) {
$future_value = ($future_value + ($future_value * $interest_rate * .01));
}
if (isset($compoundMonthly)) {
$compoundMonthly = 'Yes';
} else {
$compoundMonthly = 'No';
}
return $future_value;
}
function currency_format($investment_f, $investment, $future_value, $future_value_f){
// apply currency formatting
$investment_f = '$' . number_format($investment, 2);
$future_value_f = '$' . number_format($future_value, 2);
return $investment_f;
}
// apply percent formatting
function percent_format($interest_rate_f, $interest_rate, $yearly_rate_f){
$interest_rate_f = number_format($interest_rate, 2) . '%';
$yearly_rate_f = $interest_rate . '%';
return $yearly_rate_f;
}
}
just format the $future_value after calculating growth:
$years=2;
$interest_rate=4;
$future_value=11698.58;
for ($i = 1; $i <= $years; $i++) {
$future_value = ($future_value + ($future_value * $interest_rate * .01));
}
echo $future_value;
$future_value_f = '$' . number_format($future_value, 2);
echo "<br>$future_value_f";
return $future_value_f; // you weren't returning the formatted value

How can I improve this method. Is there any php native method available to match the range?

I want to refactor this method
public function getRange($currentWeight, $maxWeight)
{
$shades = array(
'0-10' => 'Range0-10',
'10-20' => 'Range10-20',
'20-30' => 'Range20-30',
'30-40' => 'Range30-40',
'40-50' => 'Range40-50',
'50-60' => 'Range50-60',
'60-70' => 'Range60-70',
'70-80' => 'Range70-80',
'80-90' => 'Range80-90',
'90-100' => 'Range90-100'
);
$weightPercent = ($currentWeight * 100) / $maxWeight;
foreach ($shades as $colorRange => $colorClass) {
$range = explode('-', $colorRange);
if ($weightPercent >= $range[0] && $weightPercent <= $range[1]) {
$selectedColor = $colorClass;
}
}
return $selectedColor;
}
Is there any native php function available which can give me the range of a number or is there any other way of doing this better?
Any help would be greatly appreciated.
my version:
public function getRange($currentWeight, $maxWeight)
{
$weight = intval(($currentWeight * 100) / $maxWeight / 10) * 10;
return 'Range' . $weight .'-' . ($weight +10);
}
You need something to keep your values in range:
public function getRange($currentWeight, $maxWeight){
$range_base = intval(($currentWeight * 100) / $maxWeight / 10) * 10;
if($range_base >= 0 && $range_base <= 100 && $currentWeight<=$maxWeight){
if($range_base == 100) { $range_base = $range_base - 10; }
return 'Range' . $range_base .'-' . ($range_base +10);
}else{
return false; // Out of range
}
}
Another version using range, bcsub, array_search and array_slice functions:
function getRange($currentWeight, $maxWeight)
{
if ($currentWeight > $maxWeight) { // considering max threshold
throw new Exception("weight is out of range!");
}
$colorRange = range(0, 100, 10);
$weightPercent = ($currentWeight * 100) / $maxWeight;
$lower_boundary_key = array_search(intval(bcsub(floor($weightPercent), $weightPercent % 10, 0)), $colorRange);
$range = array_slice($colorRange, $lower_boundary_key, 2);
return 'Range' . implode("-", $range);
}
print_r(getRange(41.5, 200)); // outputs: "Range20-30"
print_r(getRange(201.5, 200)); // will throw "Exception: weight is out of range! ..."

How to check if an integer is within a range of numbers in PHP?

How can I check if a given number is within a range of numbers?
The expression:
($min <= $value) && ($value <= $max)
will be true if $value is between $min and $max, inclusively
See the PHP docs for more on comparison operators
You can use filter_var
filter_var(
$yourInteger,
FILTER_VALIDATE_INT,
array(
'options' => array(
'min_range' => $min,
'max_range' => $max
)
)
);
This will also allow you to specify whether you want to allow octal and hex notation of integers. Note that the function is type-safe. 5.5 is not an integer but a float and will not validate.
Detailed tutorial about filtering data with PHP:
https://phpro.org/tutorials/Filtering-Data-with-PHP.html
Might help:
if ( in_array(2, range(1,7)) ) {
echo 'Number 2 is in range 1-7';
}
http://php.net/manual/en/function.range.php
You could whip up a little helper function to do this:
/**
* Determines if $number is between $min and $max
*
* #param integer $number The number to test
* #param integer $min The minimum value in the range
* #param integer $max The maximum value in the range
* #param boolean $inclusive Whether the range should be inclusive or not
* #return boolean Whether the number was in the range
*/
function in_range($number, $min, $max, $inclusive = FALSE)
{
if (is_int($number) && is_int($min) && is_int($max))
{
return $inclusive
? ($number >= $min && $number <= $max)
: ($number > $min && $number < $max) ;
}
return FALSE;
}
And you would use it like so:
var_dump(in_range(5, 0, 10)); // TRUE
var_dump(in_range(1, 0, 1)); // FALSE
var_dump(in_range(1, 0, 1, TRUE)); // TRUE
var_dump(in_range(11, 0, 10, TRUE)); // FALSE
// etc...
if (($num >= $lower_boundary) && ($num <= $upper_boundary)) {
You may want to adjust the comparison operators if you want the boundary values not to be valid.
You can try the following one-statement:
if (($x-$min)*($x-$max) < 0)
or:
if (max(min($x, $max), $min) == $x)
Some other possibilities:
if (in_array($value, range($min, $max), true)) {
echo "You can be sure that $min <= $value <= $max";
}
Or:
if ($value === min(max($value, $min), $max)) {
echo "You can be sure that $min <= $value <= $max";
}
Actually this is what is use to cast a value which is out of the range to the closest end of it.
$value = min(max($value, $min), $max);
Example
/**
* This is un-sanitized user input.
*/
$posts_per_page = 999;
/**
* Sanitize $posts_per_page.
*/
$posts_per_page = min(max($posts_per_page, 5), 30);
/**
* Use.
*/
var_dump($posts_per_page); // Output: int(30)
using a switch case
switch ($num){
case ($num>= $value1 && $num<= $value2):
echo "within range 1";
break;
case ($num>= $value3 && $num<= $value4):
echo "within range 2";
break;
.
.
.
.
.
default: //default
echo "within no range";
break;
}
I've created a simple helper function.
if ( !function_exists('number_between') )
{
/**
* number_between
*
* #param {integer} $number
* #param {array} $range [min, max]
* #return {boolean}
*/
function number_between(
int $number,
array $range
){
if(
count($range) !== 2 ||
is_numeric($range[0]) === FALSE ||
is_numeric($range[1]) === FALSE
){
throw new \Exception("number_between second parameter must contain two numbers.", E_WARNING);
}
if(
in_array($number, range($range[0], $range[1]))
){
return TRUE;
}else{
return FALSE;
}
}
}
Another way to do this with simple if/else range. For ex:
$watermarkSize = 0;
if (($originalImageWidth >= 0) && ($originalImageWidth <= 640)) {
$watermarkSize = 10;
} else if (($originalImageWidth >= 641) && ($originalImageWidth <= 1024)) {
$watermarkSize = 25;
} else if (($originalImageWidth >= 1025) && ($originalImageWidth <= 2048)) {
$watermarkSize = 50;
} else if (($originalImageWidth >= 2049) && ($originalImageWidth <= 4096)) {
$watermarkSize = 100;
} else {
$watermarkSize = 200;
}
I created a function to check if times in an array overlap somehow:
/**
* Function to check if there are overlapping times in an array of \DateTime objects.
*
* #param $ranges
*
* #return \DateTime[]|bool
*/
public function timesOverlap($ranges) {
foreach ($ranges as $k1 => $t1) {
foreach ($ranges as $k2 => $t2) {
if ($k1 != $k2) {
/* #var \DateTime[] $t1 */
/* #var \DateTime[] $t2 */
$a = $t1[0]->getTimestamp();
$b = $t1[1]->getTimestamp();
$c = $t2[0]->getTimestamp();
$d = $t2[1]->getTimestamp();
if (($c >= $a && $c <= $b) || $d >= $a && $d <= $b) {
return true;
}
}
}
}
return false;
}
Here is my little contribution:
function inRange($number) {
$ranges = [0, 13, 17, 24, 34, 44, 54, 65, 200];
$n = count($ranges);
while($n--){
if( $number > $ranges[$n] )
return $ranges[$n]+1 .'-'. $ranges[$n + 1];
}
I have function for my case
Use:
echo checkRangeNumber(0);
echo checkRangeNumber(1);
echo checkRangeNumber(499);
echo checkRangeNumber(500);
echo checkRangeNumber(501);
echo checkRangeNumber(3001);
echo checkRangeNumber(999);
//return
0
1-500
1-500
1-500
501-1000
3000-3500
501-1000
function checkRangeNumber($number, $per_page = 500)
{
//$per_page = 500; // it's fixed number, but...
if ($number == 0) {
return "0";
}
$num_page = ceil($number / $per_page); // returns 65
$low_limit = ($num_page - 1) * $per_page + 1; // returns 32000
$up_limit = $num_page * $per_page; // returns 40
return "$low_limit-$up_limit";
}
function limit_range($num, $min, $max)
{
// Now limit it
return $num>$max?$max:$num<$min?$min:$num;
}
$min = 0; // Minimum number can be
$max = 4; // Maximum number can be
$num = 10; // Your number
// Number returned is limited to be minimum 0 and maximum 4
echo limit_range($num, $min, $max); // return 4
$num = 2;
echo limit_range($num, $min, $max); // return 2
$num = -1;
echo limit_range($num, $min, $max); // return 0
$ranges = [
1 => [
'min_range' => 0.01,
'max_range' => 199.99
],
2 => [
'min_range' => 200.00,
],
];
foreach($ranges as $value => $range){
if(filter_var($cartTotal, FILTER_VALIDATE_FLOAT, ['options' => $range])){
return $value;
}
}
Thank you so much and I got my answer by adding a break in the foreach loop and now it is working fine.
Here are the updated answer:
foreach ($this->crud->getDataAll('shipping_charges') as $ship) {
if ($weight >= $ship->low && $weight <= $ship->high) {
$val = $ship->amount;
break;
}
else
{
$val = 900;
}
}
echo $val ;

Categories