Sum only values 1 from array - php

I have array with variables from $qA01_1 up to $qA30_5 (150 variables). Some of the variables can have value 0 or 1 or 5 (example $qA21_3 = 0 or 1 or 5). And I would like to know how to make sum of all variables which have value 1.
Here part of array
$qA01_1 = $_SESSION['qA01_1']; // example: $qA01_01 can have value 0 or 1 or 5, like other variables
$qA01_2 = $_SESSION['qA01_2']; // $qA01_02 = 0 or 1 or 5
$qA01_3 = $_SESSION['qA01_3']; // $qA01_03 = 0 or 1 or 5
$qA01_4 = $_SESSION['qA01_4']; // $qA01_04 = 0 or 1 or 5
$qA01_5 = $_SESSION['qA01_5']; // $qA01_05 = 0 or 1 or 5
$qA02_1 = $_SESSION['qA02_1']; // $qA02_01 = 0 or 1 or 5
$qA02_2 = $_SESSION['qA02_2']; // $qA02_02 = 0 or 1 or 5
$qA02_3 = $_SESSION['qA02_3']; // $qA02_03 = 0 or 1 or 5
$qA02_4 = $_SESSION['qA02_4']; // $qA02_04 = 0 or 1 or 5
$qA02_5 = $_SESSION['qA02_5']; // $qA02_05 = 0 or 1 or 5
// up to...
$qA30_1 = $_SESSION['qA30_1']; // $qA30_01 = 0 or 1 or 5
$qA30_2 = $_SESSION['qA30_2']; // $qA30_02 = 0 or 1 or 5
$qA30_3 = $_SESSION['qA30_3']; // $qA30_03 = 0 or 1 or 5
$qA30_4 = $_SESSION['qA30_4']; // $qA30_04 = 0 or 1 or 5
$qA30_5 = $_SESSION['qA30_5']; // $qA30_05 = 0 or 1 or 5
Here is proposal but not work. I´m begginer, please for help.
$values = [];
for($i=1;$i<=30;$i++)
{
foreach([1,2,3,4,5] as $index)
{
if(${'qA'.str_pad($i, 2, "0", STR_PAD_LEFT).'_'.$index} == 1)
{
$values[] = ${'qA'.str_pad($i, 2, "0", STR_PAD_LEFT).'_'.$index};
}
}
}
echo $values;

Just loop through the $_SESSION array:
// This is where we'll hold all the saved numbers
// from values ending with _1
$array_of_numbers = [];
// Loop through each session
foreach ( $_SESSION as $key => $val )
{
// Only save the keys that match and equal 1
if ( preg_match('/^qA\d{2}?_\d$/', $key, $matches) && $val == 1 )
{
$array_of_numbers[] = $val;
}
}
// Sum the numbers that we gathered
$sum_of_array = array_sum($array_of_numbers);

If you just want a sum, you don't need the $values array. Just add the value to a $sum variable.
$sum = 0;
for($i=1;$i<=30;$i++)
{
foreach([1,2,3,4,5] as $index)
{
$var = 'qA'.str_pad($i, 2, "0", STR_PAD_LEFT).'_'.$index
if(${$var} == 1)
{
$sum += ${$var};
}
}
}
echo $sum;
BTW, you can't echo an array. If you want to see the contents of an array, use var_dump($values); or print_r($values);

Time for a rethink. No reason to unpack the array like you are doing.
Lets put the $_SESSION values that we are interested in into a new array and work with that. (not necessary to put in to a new array, I just prefer to not work with the super global variables more than necessary)
//Create new array
$myArray = [];
foreach( $_SESSION as $key=>$val ){
if( preg_match('/qA\d{2}_[1-5]/', $key) ){
$myArray[$key] = $val;
}
}
$sum = 0;
foreach( $myArray as $key=>$val ){
if( preg_match('/qA\d{2}_1/', $key) ){
$sum += $val;
}
}
var_dump($sum);

Since the logic here is a bit confusing, I think separating it out into a couple "self-documenting" functions would be better practice. Something like this should work:
$sum = 0;
for ($i = 1; $i <= 30; $i++) {
for ($j = 1; $j <= 5; $j++) {
$qa_index = qa_index($i, $j);
if ($_SESSION[$qa_index] == 1)
$sum++; // no need to _actually_ sum since it's just 1
}
}
function qa_index($major, $minor) {
return 'qA'.left_pad_zeros($major).'_'.$minor."\n";
}
function left_pad_zeros($val, $pad_amount = 2) {
return str_pad($val, $pad_amount, '0', STR_PAD_LEFT);
}
EDIT: I imagine some people might think functions are unnecessary overhead here. And that may be IF whatever application is using this NEEDS to squeeze out every little bit of performance improvement they can. However, if that's not the case, I think this is much better practice as it is much easier to read and maintain.

$TotalVal = 0;
for($i=1; $i<=5; $i++){
for($j=1; $j<=5; $j++){
If($i<10){
$StrVar = 'qA0'.$j.'_'.$i.'[0]'; // considering ur using array if not remove [0].
If ($$StrVar == 1)
$TotalVal = $TotalVal + $$StrVar;
}else{
$StrVar = 'qA'.$j.'_'.$i.'[0]';
If ($$StrVar == 1)
$TotalVal = $TotalVal + $$StrVar;
}
}
}
echo $TotalVal;
This will give you sum of all values which is having 1 if u need 5 change in if condition

Related

PHP Shouldnot Repeat and should be from an array

I'm trying to build a script that does two thing.
1) The Numbers should not repeat.
2) The numbers should be from an array called $id.
<?php
$a = array(); // final array which will have our id's to display
$id = array(1, 3, 5, 7, 9); //final array should contain a number only from this list
$itemstoshow = 3; // how many items to display
for($i = 0; $i < $itemstoshow; $i++) {
do {
$a[$i] = assignid(9);
$chkid = checkeer($a[$i], $i);
$chkdata = chkdata($a[$i], $i);
} while($chkdata == "nonexist" or $chkid == "repeatedid");
}
// display numbers in the array
for($i = 0; $i < $itemstoshow; $i++) {
echo "Item " . $a[$i] . "--------";
}
// check for redundancy function
function checkeer($x, $y)
{ //first parameter is query aray second is counter
global $a;
$err = 0;
// check if repeating number
for($i = 0; $i <= $y - 1; $i++) {
if($x == $a[$i]) {
$err = 1;
}
}
if($err == 1) {
return "repeatedid";
}
}
//check if array $a holds value from $id or not
function chkdata($x, $y)
{
global $a;
global $id;
for($i = 0; $i <= $y - 1; $i++) {
if($x !== $id[$i]) {
return "nonexist";
}
}
}
//assign id function
function assignid($x)
{
return rand(1, $x);
}
problem number 1 solved problem number 2 still not solved please help me.
the code should show 3 numbers from 1 to 9 which donot repeat and are in the array $id
You could use a combination of array_rand and array_map to get random values from the array that has the values your basing the randomization. Take a look:
$id = array(1,3,5,7,9); //final array should contain a number only from this list
$itemstoshow = 3;
$values = array_map(function($item) use($id){
return $id[$item];
}, array_rand($id, $itemstoshow));
print_r($values);
Output:
Array
(
[0] => 1
[1] => 3
[2] => 9
)
Running again:
Array
(
[0] => 3
[1] => 7
[2] => 9
)
You can use array_rand that selects random keys:
$id = array(1,3,5,7,9);
$result = array_intersect_key($id, array_flip(array_rand($id, 3)));
Or you can shuffle the array and take for example the 3 first items:
$id = array(1,3,5,7,9);
$temp = $id;
shuffle($temp);
for ($i = 0; $i < 3; $i++) {
$result[] = $temp[$i];
}

Identify repeating pattern using PHP

I need to find the number of records that are greater than a specific float and find the group of data that repeat the most. For example, I have the data below and I need to find how many entries have values > 4.
1.5
1.7
4.5
4.7
4.8
1.4
4.5
4.9
In the above data the longest continuous repetition of values greater than 4 is 4.5,4.7,4.8. Therefore the total I would like returned should be 3. As you can see the pattern breaks after 4.8 since the number is 1.4 above. Is there a way to identify this pattern?
Try this, I have used here an array:
$arr = array(
0 => '1.5',
1 => '1.7',
2 => '4.5',
3 => '4.7',
4 => '4.8',
5 => '1.4',
6 => '4.5',
7 => '4.9'
);
$chk_val = 4; // value which is checking
$cnt = 0;$inc = 0;
foreach ($arr as $i => $val) {
if ($val > $chk_val) {
$inc++;
if ($inc > $cnt) { $cnt = $inc;}
} else {
$inc = 0;
}
}
echo $cnt;
try this
$n = 4; // number to check
$count = 0;
$max = 0;
$ele = array(1.5, 1.7, 4.5, 4.7, 4.8, 1.4, 4.5, 4.9);
for ($i = 0; $i < count($ele); $i++) {
if ($ele[$i] >= $n) { // check for greater element than given number
$count++; // increase consecutive counter variable
$arr[$max] = $count; //save continues max counter to array
} else {
$count = 0; //reset consecutive counter
$max++;
}
}
echo max($arr);
Quick and dirty...
function findNums($nums, $min = 4) {
$groups = array();
$groupcounts = array();
$groupindex = 0;
foreach($nums as $num) {
if($num > $min) {
$groups[$groupindex][] = $num;
if(array_key_exists($groupindex, $groupcounts)) {
$groupcounts[$groupindex]++;
} else {
$groupcounts[$groupindex] = 1;
}
} else {
$groupindex++;
}
}
return array($groupcounts, $groups);
}
// $your_numbers is your list
$nums = array_map('trim', explode("\n", $your_numbers));
$result = findNums($nums);
$counts = $result[0];
$maxcount = max($counts);
$groups = $result[1];
echo "max count is ".$maxcount." with values:\n";
$key = array_search($maxcount, $counts);
var_dump($groups[$key]);

How to find the mode of an array in PHP

I have an array that has been sorted from low to high which has over 260k values in. I have found out the mean(average) and median of the array just need to find out the mode?
I cannot use any mathematical functions that PHP has, it has to be all done manually.
I would like it so there could be just one value that is the mode but then there can be multiple values that can be the mode. I also need to be able to record the number of times that the value is stored. For example the number 51 appears 6 times so I can print both values.
This is my code so far:
$amountRecords = 0;
$totalValue = 0;
$valueArray = array();
// reads in csv file
$handle = fopen('Task1-DataForMeanMedianMode.csv', 'r');
// to skip the header names/values
fgetcsv($handle);
// creates array containing variables of csv file in ascending order
while(($row = fgetcsv($handle, "\r")) != FALSE)
{
// if amountRecords equals 0
if($amountRecords == 0)
{
// adds value from csv to array
$valueArray[] = $row[1];
} // else amountRecords does not equal 0
else
{
// if the value in array location before is greater than the current value from the csv file
if($valueArray[$amountRecords - 1] > $row[1])
{
// the current array location becomes the one in the location before
$valueArray[] = $valueArray[$amountRecords - 1];
// add the value from the csv to the location before
$valueArray[$amountRecords - 1] = $row[1];
} // if the value in the location before is not greater than the current value in the csv file
else
{
// adds value from csv to array
$valueArray[] = $row[1];
}
}
// calculates the total value of the values in csv file
$totalValue = $totalValue + $row[1];
// calculates the number of values in the csv file
$amountRecords++;
}
// calculate average value of payments
$averageValue = $totalValue / $amountRecords;
// limit integer to 2 decimal place
$average = number_format($averageValue,2,'.','');
// finds middle value
$middle = floor(($amountRecords / 2) - 1);
// calculates the median value
// if array size is even
if($amountRecords % 2 == 0)
{
// calculates median
$median = $valueArray[$middle];
}
else // if array size is odd
{
// calculate low and high values
$low = $valueArray[$middle];
$high = $valueArray[$middle + 1];
// calculates median
$median = (($low + $high) / 2);
}
// works out mode
// creates array count
$count = array();
// for each value in the valueArray
foreach( $valueArray as $value )
{
if( isset( $count[$value] ))
{
$count[$value]++;
}
else
{
$count[$value] = 1;
}
}
$mostCommon = "";
$iter = 0;
foreach( $count as $k => $v )
{
if( $v > $iter )
{
$mostCommon = $k;
$iter = $v;
}
}
$modeArray = array( "mode" => $mostCommon , "count" => $iter );
The mode of a numerical set is the number that occurs the most often. You can do this with PHP using code similar to the following:
$values = array_count_values($valueArray);
$mode = array_search(max($values), $values);
Simple!
$arr = array(4,6,7,1,4,7,4,7,1);
$freq = array();
for($i=0; $i<count($arr); $i++)
{
if(isset($freq[$arr[$i]])==false)
{
$freq[$arr[$i]] = 1;
}
else
{
$freq[$arr[$i]]++;
}
}
$maxs = array_keys($freq, max($freq));
for($i=0; $i<count($maxs); $i++)
{
echo $maxs[$i] . ' ' . $freq[$maxs[$i]];
echo '<br />';
}
Mathematical only solution:
//sample data
$dataArr = ["1", "3", "5", "1", "3", "7", "1", "8", "1"];
//a multidimensional array to hold the keys (extracted fro above) and their values (number of occurrences)
$multiDArr = [];
for ($i = 0; $i < count($dataArr); $i++) {
$key = $dataArr[$i];
if (isset($multiDArr[$key])) {
//key already exists; increment count of its value
$multiDArr[$key] = $multiDArr[$key] + 1;
} else {
//key does nto exist; add it and an inital value of 1
$multiDArr[$key] = 1;
}
}
$highestOccuring = 0;
$highestOccuringKey = null;
foreach ($multiDArr as $key => $value) {
if ($value > $highestOccuring) {
$highestOccuring = $value;
$highestOccuringKey = $key;
}
}
echo "MODE / highest occuring key: " . $highestOccuringKey;
/** find array mode, most often see value
* #param list(int) $a_in
* #return list(int)
*/
function array_mode(array $a_in): array{
$a_freq = [];
foreach( $a_in as $v ) {
if (!isset($a_freq[$v])) {
$a_freq[$v] = 0;
}
$a_freq[$v]++;
}
$a_maxs = array_keys($a_freq, max($a_freq));
return $a_maxs;
}
// test code
$a_in = [4,6,7,1,4,7,4,7,1];
array_mode( $a_in);
This will take values and turn it into an array of the modes. For Example: print_r(get_mode(1,2,2,3,3,3,4,4,5,5,5,6,7,8,9)); will return,
Array
(
[0] => Array
(
[value] => 3
[count] => 3
)
[1] => Array
(
[value] => 5
[count] => 3
)
)
code:
function get_mode(...$inputArray){
$max=0;
return array_reduce(
array_values(array_reduce(array_values($inputArray),function($talliedArray,$inputNode){
if(isset($talliedArray[(string)$inputNode]))
$talliedArray[(string)$inputNode]['count']++;
else
$talliedArray[(string)$inputNode] = [
'value' => $inputNode,
'count' => 1
];
return $talliedArray;
},[])),function($modeArray,$talliedNode)use(&$max){
if($talliedNode['count'] < $max) return $modeArray;
if($talliedNode['count']=== $max) return array_merge($modeArray,[$talliedNode]);
//if count > $max
$max = $talliedNode['count'];
return [$talliedNode];
},[]);
}
This satisfies the "no math functions", the "multiple return modes" and the "have the value and number of occurrences returned".
This will only really work with strings and numbers. It will go weird with booleans, Objects and Arrays.

Recursively find combinations in PHP

I have the following structure:
A 3
B 2
C 2
D 1
E 0
While letters represent the actual value of the element, numbers represent the level of the element. I want to be able to output the following:
A B D E
A C D E
the code that I have right now is not doing the job properly and I need to find a recursive way to address the problem. Any help would be really appreciated.
<?php
// An array that holds the values
$values = array();
$values[] = "A";
$values[] = "B";
$values[] = "C";
$values[] = "D";
$values[] = "E";
// An array that holds the levels
$levels = array();
$levels[] = 3;
$levels[] = 2;
$levels[] = 2;
$levels[] = 1;
$levels[] = 0;
// We are asuming that 3 is the heighest level
$startingLevel = 3;
// this array will holds all combinations. each group is seperated by a |
$results = array();
for($i = 0; $i < count($values); $i++)
{
$thisValue = $values[$i];
$thisLevel = $levels[$i];
if($thisLevel == $startingLevel)
{
$results[] = $thisValue;
$j = 0;
$k = $i;
$limit = $thisLevel;
while($j < $thisLevel)
{
if($levels[$k] < $limit)
{
$results[] = $values[$k];
$limit = $levels[$k];
$j++;
}
$k++;
}
// separating groups by |
$results[] = "|";
}
}
// Show results
print_r($results);
?>
Most likely what you want is to generate all combinations with O((n^2-n)/2) and then compare it with the 2nd array and also what you want is to look at my example in Javascript. Array Waypoints hold your first Array. Array wayStr holds your solution. Then you need only to iterate through the solution and compare it with your 2nd array.
function getWayStr(curr) {
var nextAbove = -1;
for (var i = curr + 1; i < waypoints.length; ++i) {
if (nextAbove == -1) {
nextAbove = i;
} else {
wayStr.push(waypoints[i]);
wayStr.push(waypoints[curr]);
}
}
if (nextAbove != -1) {
wayStr.push(waypoints[nextAbove]);
getWayStr(nextAbove);
wayStr.push(waypoints[curr]);
}
}
Separate the different levels and use permutation:
lexicographic ordering

How to assign a rank number to an array when ties exist

I am struggling to know where to start when trying to assign ranks to the numeric values in an array when there are ties. So, for example, I need to turn an array like the following:
myarray = (4,76,34,13,34)
into another array like:
myarray2 = (1,5,3.5,2,3.5)
Basically, when the same number occurs more than once in the array, the assigned rank to those numbers is the average of the ranks. So, instead of the two 34s being ranked 3 and 4 they both get assigned 3.5. Similarly, if there were 3 copies of 34 then the 3 assigned ranks would be divided by 3. Any help would be much appreciated!
Many thanks,
Adam
I had fun with this one!
function rank($input)
{
$output = array();
$ranking = $input; sort($ranking); $ranking = array_flip($ranking);
$last_val = -1;
foreach($ranking as $key => $val){
$repetitions = ($val-$last_val-1);
$last_val = $val;
if($repetitions) {
$ranking[$key] = (($val*($repetitions+1))-($repetitions+1)*(($repetitions)/2))/($repetitions+1)+1 ;
} else {
$ranking[$key] = $val+1;
}
}
foreach($input as $key => $val){
$output[$key] = $ranking[$val];
}
return $output;
}
Use it like this:
$a = array(4,76,34,13,34);
$c = rank($a);
print_r($c);
will output:
Array
(
[0] => 1
[1] => 5
[2] => 3.5
[3] => 2
[4] => 3.5
)
wich is the same as:
Array(1, 5, 3.5, 2, 3.5)
as expected!
Here is one way to do it.
<?php
$myarray = array(4,76,34,13,34);
$sorted_array = $myarray;
$grouped_array = array();
sort($sorted_array);
foreach ($sorted_array as $rank => $entry) {
// Initialize the entry if it doesn't already exist
if (empty($grouped_array[$entry])) {
$grouped_array[$entry]['count'] = 1.0;
$grouped_array[$entry]['total'] = $rank + 1; // Account for 0-based array
} else {
$grouped_array[$entry]['count'] += 1.0;
$grouped_array[$entry]['total'] += $rank + 1; // Account for 0-based array
}
}
$myarray2 = array();
foreach ($myarray as $entry) {
// Get the average
$myarray2[] = $grouped_array[$entry]['total'] / $grouped_array[$entry]['count'];
}
I assume you also need to handle the cases where there are three or four or n values tied at the same rank.
I'm no PHP guru, but here's an approach (pseudo code) to defining a rank function:
define a = original array
define s = a.Sorted
define rank(n) = (s.FirstIndexOf(n) + s.LastIndexOf(n)) / 2
You may need to work a few examples on paper to convince yourself that this works even for triples and higher; it's reliant on s being sorted so that duplicates are adjacent.
The accepted solution (and others too) seem to be way more complicated than they need to be:
function Rank($data) {
$count = 0;
$unique = $data; sort($unique);
$unique = array_count_values($unique);
foreach ($unique as $key => $frequency) {
foreach (range(1, $frequency) as $i) {
$unique[$key] += $count++;
}
$unique[$key] /= $frequency;
}
foreach ($data as $key => $value) {
$data[$key] = $unique[$value];
}
return $data;
}
Example (demo):
print_r(Rank(array(4, 76, 34, 13, 34))); // 1; 5; 3.5; 2; 3.5
print_r(Rank(array(4, 76, 34, 13, 34, 34))); // 1; 6; 4; 2; 4; 4

Categories