Adding values together based on their position in PHP - php

Each number has a corresponding value with it. There are many numbers which I can demonstate in a table here with their appropriate values:
[N] [V] N=Number V=Value
2 19
4 19
6 19
8 21
10 21
12 22
14 23
16 23
18 23
20 33
22 37
24 42
26 45
28 48
30 50
32 55
34 61
36 66
38 72
40 78
42 155
44 179
46 202
48 233
50 360
There is a process that a user will go through where they go from Number x to Number y. The values inbetween those numbers need to get added together. So for example, let's say a user goes from 16 to 38:
[N] [V] N=Number V=Value
2 19
4 19
6 19
8 21
10 21
12 22
14 23
[16][23]--
18 23 |
20 33 |
22 37 |
24 42 |
26 45 |
28 48 |---- All of these values get added together
30 50 |
32 55 |
34 61 |
36 66 |
[38][72]--
40 78
42 155
44 179
46 202
48 233
50 360
So the users total value would equal be:
23 + 23 + 33 + 37 + 42 + 45 + 48 + 50 + 55 + 61 + 66 + 72
Total Value = 555
The problem is, is that I have no idea how I to put this together in code. Like how to assign these values to their specific number and how to add those specific values together to get me a result. In PHP I simply do not know where to begin with this.
Also, the approximate values from the numbers can be represented by this equation:
v = 11.218e^(0.057n)
I would imagine this would be useful in making this whole process easier but I am still not sure how to go about implementing all of this. Any help would be very much apprieciated!

Put each each number with it's corresponding value into an array making number as key and value pair like this.
<?php
$arr = array(
2=> 19,
4=> 19,
6=> 19,
8=> 21,
10=> 21,
12=> 22,
14=> 23,
16=> 23,
18=> 23,
20=> 33,
22=> 37,
24=> 42,
26=> 45,
28=> 48,
30=> 50,
32=> 55,
34=> 61,
36=> 66,
38=> 72,
40=> 78,
42=> 155,
44=> 179,
46=> 202,
48=> 233,
50=> 360,
);
?>
Loop array with foreach loop like this
<?php
$sum = 0;
foreach($arr as $k => $v) {
if($k >= 16 && $k <= 38)
$sum += $v;
}
?>
There is another way using for loop statement, put both number in two separate array ($n and $v). Iterate the loop of the first array($n) and find the value from second array($v) through the index number of first array. But both array count should have same.
Example-
<?php
$n = array(2,4,6,8,10,12,14,16,18,20);
$v = array(19,19,19,21,21,22,23,23,23,33);
$sum = 0;
for($i=0, $i<count($n); $i++) {
if($n[$i] >= 16 && $n[$i] <= 38)
$sum += $v[$i];
}
?>

You would put your number and value pairs into an key / value array. So a shortened version of your test data would look like this:
$myDataStore = array(
"2" => "19",
"4" => "19",
"6" => "19",
"8" => "21",
"10" => "21",
"12" => "22",
"14" => "23",
"16" => "23",
"18" => "23",
"20" => "23"
);
Now you need a function to calculate your sum given a range as defined by starting and ending numbers.
function getRangeTotal($array, $startNumber, $endNumber){
$total = 0;
foreach($array as $key => $value){
if($key >= $startNumber && $key <= $endNumber){
$total = $total + $value;
}
}
return $total;
}
If you run the above function
getRangeTotal($myDataStore, 6, 12);
You'll get 83

Here is how you can do this using foreach
// first store you data to an array.
$kv = array(
2 => 19, 4 => 19, 6 => 19, 8 => 21,
10 => 21, 12 => 22, 14 => 23, 16 => 23,
18 => 23, 20 => 33, 22 => 37, 24 => 42,
26 => 45, 28 => 48, 30 => 50, 32 => 55,
34 => 61, 36 => 66, 38 => 72, 40 => 78,
42 => 155, 44 => 179, 46 => 202,48 => 233,
50 => 360
);
$start = 16;
$end = 32;
$sum = 0; //variable to keep sum
$n = 0; //variable to keep count
//loop through the array
foreach ($kv as $k => $v){
if ($k >=$start && $k <= $end){ //if key is in your range
$sum += $v; //add value to sum
$n ++; // increment count
}
}
$v = 11.218*pow(M_E,0.057*$n); //calculate the approximate values
echo "$sum\n$v\n";
Also refer to : pow and Predefined Constants

Related

Combine Words and Numbers in Arrays using PHP

I want to combine the two arrays in my results
MY CODE
<?php
/* Designated level for each exp
Level 2 - 23 exp
Level 3 - 34 exp
Level 4 - 45 exp
Level 5 - 56 exp
Level 6 - 68 exp
Level 7 - 79 exp
Level 8 - 90 exp
Level 9 - 101 exp
Level 10 - 112 exp
Level 11 - 123 exp
Level 12 - 134 exp
Level 13 - 145 exp
Level 14 - 156 exp
Level 15 - 168 exp
Level 16 - 179 exp
*/
$limit = 100000-99318;
// Level
$arrlevel = array ('Level 2','Level 3','Level 4','Level 5','Level 6','Level 7','Level 8','Level 9','Level 10','Level 11','Level 12','Level 13','Level 14','Level 15','Level 16');
// Exp
$array = array (23,34,45,56,68,79,90,101,112,123,134,145,156,168,179);
$array = array_filter($array, function($var) use ($limit) {
return ($var <= $limit);
});
$num = count($array);
$total = pow(2, $num);
$out = array();
for ($i = 0; $i < $total; $i++) {
$comb = array();
for ($j = 0; $j < $num; $j++) {
// is bit $j set in $i?
if (pow(2, $j) & $i){
$comb[] = $array[$j];
}
}
if (array_sum($comb) == $limit)
{
$out[] = $comb;
}
}
array_multisort(array_map('count', $out), SORT_ASC, $out);
$out = array_unique($out, SORT_REGULAR);
$m = 1;
foreach($out as $result)
echo "<b>Possible Answer ". $m++. " : </b> " .implode(', ', $result)."
<br><br>";
?>
Output:
Possible Answer 1 :
23, 34, 45, 68, 79, 90, 112, 179
Possible Answer 2 :
23, 34, 45, 68, 79, 90, 123, 168
Possible Answer 3 :
23, 34, 45, 68, 79, 101, 112, 168
I want the ouput like this
Possible Answer 1 :
Level 2 - 23 | Level 3 - 34 | Level 4 - 45 | Level 6 - 68 | Level 7 - 79 | Level 8 - 90 | Level 10 - 112 | Level 16 - 179
-----------------------------------------
I want to combine the two arrays
(This program is about finding all combination to reach the result [Subset sum program])
You might use a mapper for the entries of Level n and the experience.
Then for the $result array in the loop you could use array_map and for each item that you are mapping use the value as the key for the $mapper array and implode using |
That will format all the possible answers in this format:
Possible Answer 1 :
Level 3 - 34 | Level 13 - 145 | Level 14 - 156 | Level 15 - 168 | Level 16 - 179
For example
$mapper = [
23 => "Level 2",
34 => "Level 3",
45 => "Level 4",
56 => "Level 5",
68 => "Level 6",
79 => "Level 7",
90 => "Level 8",
101 => "Level 9",
112 => "Level 10",
123 => "Level 11",
134 => "Level 12",
145 => "Level 13",
156 => "Level 14",
168 => "Level 15",
179 => "Level 16",
];
foreach($out as $result)
echo "<b>Possible Answer ". $m++. " : </b> " .implode(' | ', array_map(function($x) use ($mapper) {
return $mapper[$x] . " - " . $x;
}, $result))."
<br><br>";
Php demo
Just do it and do sort
$combine=array_combine($arrlevel,$array);

Loop through variables, increment by 10 and create new variable

I have $amounts eg. 31; 48; 57; 63; 79; 84 and 95
What I would like to do is loop through each “$amount”, and if they are above 50, create variable that adds 1 for each 10 increment
Eg.
$amount(57) = +1
$amount(63) = +2
$amount(79) = +3
$amount(84) = +4
$amount(95) = +5
UPDATED VERSION:
Apologies for the vague question.
I have
$amount = array(end($percentage));
eg. 47, 63, 79, 95
What I would like to have is another variable to be created eg. $to_add if $amount > 50.
Then for each $amount >= 50 add 1 to the $to_add
Should look like:
$amount(47) = NULL ($to_add = 0)
$amount(50) = $to_add = 1 – *WOULD HAVE BEEN*
$amount(63) = $to_add = 2
$amount(79) = $to_add = 3
$amount(80) = $to_add = 4 – *WOULD HAVE BEEN*
$amount(95) = $to_add = 5
Thanks for the input thus far - I am testing the feedback I have already received - thank you very much!
This should work for you:
(Here I just go through each element with array_map(), then I check if the value is over 50 and if yes I add 1 for every 10)
<?php
$amount = [31, 48, 57, 63, 79, 84, 95];
print_r($amount);
$amount = array_map(function($v){
if($v / 50 >= 1)
return ceil($v + ($v-50)/10);
return $v;
}, $amount);
print_r($amount);
?>
output:
Array ( [0] => 31 [1] => 48 [2] => 57 [3] => 63 [4] => 79 [5] => 84 [6] => 95 )
Array ( [0] => 31 [1] => 48 [2] => 58 [3] => 65 [4] => 82 [5] => 88 [6] => 100 )
Somewhat like this:
$array=array();
$i=0;
foreach($amounts as $amount){
if($amount>50){
$value=floor($amount/10);
$array[$i]=$value;
$i++;
}
}
var_dump($array);
Now $array contains the values you want. You have to adapt the code to your code since I have no idea what $amount is(I assume values of an array)

Avoiding loops in a complex calculation with arrays

I have two arrays of numbers, one containing a lot of numbers, one only a few. There are no duplicates within or between arrays:
$all = range(1, 50);
$few = array(7, 11, 19, 27, 29, 36, 40, 43);
$many = array_merge(array_diff($all, $few));
I now want to calculate the differences between each of the "few" numbers and all of the "many" that follow it but come before the next of the "few". For example, among $many, only 28 falls between 27 and 29 from $few, so I want to calculate the difference between 28 and 27. No other differences to 27 are calculated, because no other $many fall between 27 and 29. For 19 from $few I will calculate the differences to 20, 21, 22, 23, 24, 25 and 26, because they all lie between 19 and the next number from $few, which is 27.
To calculate the differences, I use loops. Here is a somewhat simplified code (which ignores the fact that there is no index [$i + 1] for the last number in $few):
$differences = array();
for($i = 0; $i < count($few); $i++) {
foreach($many as $m) {
if($m > $few[$i] && $m < $few[$i + 1]) {
$differences[] = $m - $few[$i];
}
}
}
If I have huge arrays, the loops will take a long time to run. So:
Is there a better way to calculate the differences, without using loops?
The resulting $differences looks like this:
Array $many $few
( ↓ ↓
[0] => 1 // 8 - 7 = 1
[1] => 2 // 9 - 7
[2] => 3 // 10 - 7
[3] => 1 // 12 - 11
[4] => 2
[5] => 3
[6] => 4
[7] => 5
[8] => 6
[9] => 7
[10] => 1
[11] => 2
[12] => 3
[13] => 4
[14] => 5
[15] => 6
[16] => 7
[17] => 1
[18] => 1
[19] => 2
[20] => 3
[21] => 4
[22] => 5
[23] => 6
[24] => 1
[25] => 2
[26] => 3
[27] => 1
[28] => 2
)
My basic reasoning is that as a human, I don't see two arrays that I compare:
... 16 17 18 | 20 21 22 23 24 25 26 | 28 29 30 31 ...
exclude | include | exclude
19 (27)
But rather one number line that I go along from one number to the next, and when I meet one marked "few" I will calculate all the differences to each of the following numbers, until I meet another one marked "few":
... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ...
... m m m f m m m m m m m f m m m m ...
↑ ↑ ... ↑
start calculate stop
Because it is sorted, I don't have to go over the whole $many-array number by number for every number from $few. So can we somehow take the fact into account that the arrays are ordered? Or maybe build one array that contains the markers ("f", "m") and the numbers as keys? E.g.:
$all = array("drop this", "m", "m", "m", "m", "m", "m", "f", ...);
unset($all[0]); // drops the first element with index 0
Apart from the two calls to sort(), all you need is a single loop through $many.
// Input data provided in the question
$all = range(1, 50);
$few = array(7, 11, 19, 27, 29, 36, 40, 43);
$many = array_values(array_diff($all, $few));
// Display the values to see what we are doing
echo('$few = ['.implode(' ', $few)."]\n");
echo('$many = ['.implode(' ', $many)."]\n");
//
// The actual algorithm starts here
// Sort both $few and $many
// it works fast enough and it is required for the rest of the algorithm
sort($few);
sort($many);
// Be sure the last value of $few is larger than the last value of $many
// This is needed to avoid extra checking for the last element of $few inside the loop
if (end($few) < end($many)) {
array_push($few, end($many) + 1);
}
// Extract the first two items from $few
$current = array_shift($few);
$next = array_shift($few);
// This is the result
$differences = array();
// Run only once through $many, check each item against $next
// subtract $current from it; advance when $next was reached
foreach ($many as $item) {
// Skip the items smaller than the first element from $few
if ($item < $current) {
continue;
}
// If the next element from $few was reached then advance to the next interval
while ($next < $item) {
$current = $next;
$next = array_shift($few);
}
// Here $current < $item < $next
// This echo() is for debug purposes
echo('$current = '.$current.'; $item = '.$item.'; $next = '.$next.'; difference='.($item - $current)."\n");
// Store the difference
$differences[] = $item - $current;
}

Group PHP array numbers

How I can change this:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 11
[8] => 21
[9] => 22
[10] => 23
[11] => 24
)
To this:
1-7, 11, 21-24
I have a list of numbers like this in PHP array, and I just want to make this list a little bit smaller.
2000: 3 6 7 11 15 17 25 36 42 43 45
2001: 2 3 4 5 6 9 10 11 12 13 34 37 45 46 47 48 49 50 51 52
2002: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2003: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
2004: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2005: 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2006: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2007: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
Interesting task.
Here's a demo script that does exactly what you want.
Tweak to taste.
Code
<?php
$groups = array();
$active_group = 0;
$output = array();
$output_counter = 0;
$nums = array( 1, 2, 3, 4, 5, 6, 7, 11, 21, 22, 23, 24 );
foreach( $nums as $k => $num ) {
// if this isn't the first item, and the current number
// isn't one more than the previous one, increment the counter
if( $k !== 0 && $nums[$k] !== $nums[$k-1]+1 )
$active_group ++;
// add this number to a group
$groups[ $active_group ][] = $num;
}
// take the 1st and last of each group
foreach( $groups as $group ) {
$first = array_shift( array_values($group) );
$output[$output_counter][] = $first;
$last = array_pop( array_values($group) );
if( $first !== $last )
$output[$output_counter][] = $last;
$output_counter++;
}
echo '<pre>';
print_r($output);
?>
Output
Array
(
[0] => Array
(
[0] => 1
[1] => 7
)
[1] => Array
(
[0] => 11
)
[2] => Array
(
[0] => 21
[1] => 24
)
)
A single loop will do. You need need to keep track of the "previous" iteration's value and the "starting" value for storing ranged data.
Code:
$prev = -1; // initialize out of range
foreach ($numbers as $n) {
if (!isset($start)) { // first iteration
$start = $n; // declare $start
} elseif ($n != $prev + 1) { // not consecutive
$result[] = $start == $prev ? $prev : "$start-$prev"; // store single or ranged values
$start = $n; // update $start
}
$prev = $n; // declare / update $prev
}
$result[] = $start == $prev ? $prev : $start . '-' . $prev; // store final iteration data
echo implode(', ', $result); // comma delimit the values
Output from: $numbers = [1, 2, 3, 4, 5, 6, 7, 11, 21, 22, 23, 24]; (Demo)
1-7, 11, 21-24
Output from: $numbers = [1, 3, 5, 6, 11, 21, 22, 23, 24, 26]; (Demo)
1, 3, 5-6, 11, 21-24, 26
Here is a way to both compress an array of integers into the string format you want and to expand that string format back out to an array of integers.
function compress($expanded) {
$low = -1;
$prevNum = -1;
$expanded = array_unique($expanded);
sort($expanded, SORT_NUMERIC);
foreach($expanded as $num) {
if($low == -1) {
$low = $num;
} else if($num - $prevNum > 1) {
$compact[] = ($prevNum - $low >= 1) ? sprintf("%d-%d", $low, $prevNum) : $prevNum;
$low = $num;
}
$prevNum = $num;
}
if($low != -1 ) {
$compact[] = ($num - $low >= 1) ? sprintf("%d-%d", $low, $num) : $num;
}
return implode(",", $compact);
}
public static function expand($compact) {
$expanded = Array();
$compact = explode(",", $compact);
foreach($compact as $num) {
if( is_numeric($num) ) {
$expanded[] = $num;
} else {
list($low, $high) = explode("-", $num);
if( is_numeric($low) && is_numeric($high) && $low < $high) {
for($i = $low;$i <= $high;$i++) {
$expanded[] = $i;
}
}
}
}
return $expanded;
}
//Placeholder array
$b = array();
// Slice array (where to slice)
$s = array(11, 21);
foreach ($array as $year => $a) {
for($i = 0; $i < count($a); $i++) {
for($ii = 0; $ii < count($s); $ii++) {
if($i == 0) {
$b[$year]['<' . $s[$ii]][] = $a[$i];
break;
} else if ( isset($a[$i+1]) && $a[$i] < $s[$ii] && $a[$i+1] >=$s[$ii]){
$b[$year]['<' . $s[$ii]][] = $a[$i];
if (isset($s[$ii+1])) {
$b[$year]['<' . $s[$ii+1]][] = $a[$i+1];
} else {
$b[$year]['>' . $s[$ii]][] = $a[$i+1];
}
break;
} else if ( !isset($s[$ii+1]) && $i == count($a) - 1) {
$b[$year]['>' . $s[$ii]][] = $a[$i];
break;
}
}
}
}
$array
The list of numbers
OUTPUT ($b):
array
2000 =>
array
'<11' =>
array
0 => int 3
1 => int 7
'<21' =>
array
0 => int 11
1 => int 17
'>21' =>
array
0 => int 25
1 => int 45
2001 =>
array
'<11' =>
array
0 => int 2
1 => int 10
'<21' =>
array
0 => int 11
1 => int 13
'>21' =>
array
0 => int 34
1 => int 52
2002 =>
array
'<11' =>
array
0 => int 1
1 => int 10
'<21' =>
array
0 => int 11
1 => int 20
'>21' =>
array
0 => int 21
1 => int 52
2003 =>
array
'<11' =>
array
0 => int 1
1 => int 10
'<21' =>
array
0 => int 11
1 => int 20
'>21' =>
array
0 => int 21
1 => int 51
2004 =>
array
'<11' =>
array
0 => int 1
1 => int 10
'<21' =>
array
0 => int 11
1 => int 19
'>21' =>
array
0 => int 21
1 => int 52
2005 =>
array
'<11' =>
array
0 => int 1
1 => int 10
'<21' =>
array
0 => int 11
1 => int 20
'>21' =>
array
0 => int 21
1 => int 52
2006 =>
array
'<11' =>
array
0 => int 1
1 => int 10
'<21' =>
array
0 => int 11
1 => int 20
'>21' =>
array
0 => int 21
1 => int 52
2007 =>
array
'<11' =>
array
0 => int 1
1 => int 10
'<21' =>
array
0 => int 11
1 => int 20
'>21' =>
array
0 => int 21
1 => int 52
NOTE: Just change the values (11) and (21) to suit your needs. You can add more values.
Heres an example:
$query = "SELECT '1-11' Range, COUNT(rank) rank
FROM promoted WHERE rank between 1 and 11
union all
SELECT '12-21' Range, COUNT(rank) rank
from promoted
where rank between 12 and 21
union all
SELECT '22-31' Range, count(rank) rank
from promoted
where rank between 22 and 31
union all
SELECT '32-40' Range, count(rank) rank
from promoted
where rank between 22 and 31
union all
SELECT rank, count(rank) FROM promoted WHERE rank = '40'";

taking value to next 10th position

I know that it's rather an unusual question, but I need to find next 10th position
Let me clear with an example:
I will have some numbers like
2, 5, 8, 13, 28, 35, 42, 49
I want to find the next 10th position
2 => 10
5 => 10
8 => 10
13 => 20
28 => 30
35 => 40
42 => 50
49 => 50
How can I find it, please help guys. thanks.
Sorry for poor english.
Divide by 10, ceil(), multiply by 10.
$next10th = round( $number + 5 , -1 , PHP_ROUND_HALF_DOWN )
If the number is integer, you can also use:
$next10th = $number + 9 - (($number-1) % 10)
$numbers = array(2, 5, 8, 13, 28, 35, 42, 49);
foreach ($numbers as $n) {
echo $n . ' => ' . ((floor($n / 10) + 1) * 10) . "<br />\n";
}
or
$numbers = array(2, 5, 8, 13, 28, 35, 42, 49);
foreach ($numbers as $n) {
echo $n . ' => ' . (ceil($n / 10) * 10) . "<br />\n";
}
Both output:
2 => 10
5 => 10
8 => 10
13 => 20
28 => 30
35 => 40
42 => 50
49 => 50

Categories