using array_count_values in 2 dimensional array - php

So I have array with patch number and seasons next to it, and I'm trying to count how many patches are in a season so I want to count how many $season[x][1] == 1 or 2 etc.
$patches_get = $conn->prepare("SELECT Patch_No FROM info ORDER BY Created DESC");
$patches_get->execute();
$patchesresult = $patches_get->get_result();
while($data1 = $patchesresult->fetch_assoc()){
$patches[]=$data1["Patch_No"];
}
function getseasons($patches){
$seasons = array();
foreach($patches as $patch){
if(substr($patch,0,1)!=1){
$seasons[] = array($patch, substr($patch,0,1));
}
//Checking first number if 1 it is season 1 or 2 or 3
elseif(substr($patch,0,1)==1){
if(substr($patch, 6,3)>151&&substr($patch, 6,3)<155){
$seasons[] = array($patch, 3);
}
elseif(substr($patch, 6,3)>125&&substr($patch, 6,3)<151){
$seasons[] = array($patch, 2);
}
elseif(substr($patch, 6,3)>32&&substr($patch, 6,3)<126){
$seasons[] = array($patch, 1);
}
}
}
return $seasons;
}
$seasons = getseasons($patches);
var_dump($seasons);
$fr_c=array_count_values($seasons);
echo $fr_c['1'];
Here is also a var_dump of how my array would look like http://i.imgur.com/lV1APvV.png

If I"m reading your question right, you essentially want to count the inner array without iterating through the outer? If that's the case, look into array_column()
For example, let's say I have the following array
$myArr = [
['item' => 'value1'],
['item' => 'value2']
]
Calling array column like so
array_column($myArr, 'item'); // returns an array of just the values that you can iterate through.
See here
If this isn't the answer you're looking for, please disregard.

Related

How generate column using for loop

How to make this function produce column occLvl_ loop 3 time and using explode to fetch each value from sql CONCAT. So the result will become like this.
[{
"accommodationID": "LA56",
"occLvl_0": "40.00",
"occLvl_1": "70.00",
"occLvl_2": "90.00"
}]
function getOccLevel(){
global $ehorsObj;
$occArray = array();
$sql = "SELECT accommodationID, GROUP_CONCAT(occLevelDesc) AS occLevels
FROM tblSamAccOccLevels
WHERE ACTIVE = 'y'
GROUP BY accommodationID
ORDER BY accommodationID ASC, occLevelDesc ASC ";
$GetResult = $ehorsObj->FetchData($sql, $ehorsObj->DEFAULT_PDO_CONNECTIONS);
while ($row = $GetResult->fetch()){
$occArray[] = array(
'accommodationID' => $row['accommodationID'],
);
//seem the method below is not working
for ($j = 0; $j < 3; $j++) {
$occArray["occLvl_".$j] = explode(",", $row['occLevels'])
}
}
header("Content-type: application/json");
$result = json_encode($occArray);
echo $result;
}
Result of the query
accommodationID occLevels
LA56 40.00, 70.00, 90.00
Making numerically named object properties/variables (occLvl_0 etc.) is generally a bad idea as it makes it difficult to work with them in any regular manner (e.g. using a loop). It is better practice to put the values into an array:
while ($row = $GetResult->fetch()){
$occArray[] = array(
'accommodationID' => $row['accommodationID'],
'occLvl' => explode(",", $row['occLevels'])
);
}
This will give you an output JSON that looks something like:
[
{
"accommodationID": "LA56",
"occLvl": [
40,
70,
90
]
},
{
"accommodationID": "PQ45",
"occLvl": [
30,
60,
100
]
},
...
]
And in your JS you can then iterate over the occLvl array to get the values.
If you need the data in the form you describe, then you need to iterate over the exploded occLevels value to generate the individual values, pushing them with the accommodationID into a new array and then pushing that array to $occArray:
while ($row = $GetResult->fetch()){
$this_occ = array(
'accommodationID' => $row['accommodationID'],
);
foreach (explode(",", $row['occLevels']) as $key => $occLvl) {
$this_occ["occLvl_$key"] = $occLvl;
}
$occArray[] = $this_occ;
}
Explode returns an array. You should explode before the loop and iterate through the result of that explode in the loop

Summing the values of two arrays in php

There is a problem:
After submitting a form I receive the indexed array as a SQL-query result and the goal is to sum each next array values with the values of previously received arrays and put the sums into result array
Example:
// 1st query result
$product_amount = [0 => 0.36,
1 => 0.14,
2 => 0.42]
// 2nd query result
$product_amount = [0 => 0.28,
1 => 0.12,
2 => 0.40]
// n-th query result
$product_amount = [0 => 0.16,
1 => 0.14,
2 => 0.42]
// the sum
$total = [0 => 0.80,
1 => 0.40,
2 => 1.24]
How to do it?
The code that creates an array:
function doseCount($num){
return ($num/100) * intval($_POST['portion']); //getting multiplier for productAmount() function
}
function productAmount(){
global $link; //connection to the MySQL server
if(isset($_POST['product'])){
$product_amount_query = 'SELECT va.vitamin_a, va.vitamin_b1, va.vitamin_b2, va.vitamin_b3, va.vitamin_b5,
va.vitamin_b6, va.vitamin_bc_b9, va.vitamin_b12, va.vitamin_c, va.vitamin_d, va.vitamin_e, va.biotin, va.vitamin_k,
va.flavonoids, va.lipoic_acid FROM products_list p, vitamins_amount va WHERE p.id = va.product_id AND p.name = ?';
$product_amount_stmt = mysqli_prepare($link, $product_amount_query);
mysqli_stmt_bind_param($product_amount_stmt, "s", $_POST['product']);
mysqli_stmt_execute($product_amount_stmt);
$result = mysqli_stmt_get_result($product_amount_stmt);
$product = mysqli_fetch_array($result, MYSQLI_NUM);
return $product_final_result = array_map('doseCount', $product);
mysqli_stmt_close($product_amount_stmt);
mysqli_close($link);
}
}
$product_amount = productAmount();
After submit $product_amount array gets new data and this new value must be summed with previous.
You could accomplish this by combining array_map and array_sum. If you're using PHP 5.6 or greater, which you should, you could write something like this:
$total = array_map(function (...$vals) {
return array_sum($vals);
}, ...$results);
Assuming that $results contains all of your $product_amount arrays.
If you want to build $total incrementally instead of passing all query results at once, you can do this:
// Initialize $total array
$total = [0, 0, 0];
// Update $total for each query
$total = array_map(function (...$vals) {
return array_sum($vals);
}, $total, $product_amount);
This problem can be solved with proper use of sessions:
if (empty($_SESSION['product_amount'])){
$_SESSION['product_amount'] = $product_amount;
}else{
foreach ($_SESSION['product_amount'] as $key => $value) {
$_SESSION['product_amount'][$key] += $product_amount[$key];
}
}
Special thanks to Mawia HL for his help.

How to sort a multidimensional array of columns by a specific column in PHP?

I found on the PHP documentation the function "array_multisort" that is meant to sort an array "of columns". They provide one example where the user has an array of rows and then the user has to transform this array of rows into an array of columns. In my case the array is already set by columns, such as:
tablearray
{
['Employee_ID'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['First_Name'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['LastName'] = {0 => row1, 1 => row2, 2 => row3, 3 =>row4}
}
I want to sort by Employee_ID and I need all the other columns to follow the same order. I tried:
array_multisort($tablearray['Employee_ID'], SORT_ASC);
But it only sorts the first column (which becomes a mess). The array has more than 10 columns and it changes the column names depending on the search (the columns names are its keys).
On PHP's documentation for this function, the example provided shows that the after transforming the rows array into a columns array, we should use the original array as a third parameter to match the keys - I don't have the "original" array to do the match since I didn't transform anything.
Thank you.
Desired output, as suggested by one user:
Original:
array
{
['Employee_ID'] = (1002, 4508, 0002, 1112)
['Business_Unit'] = ('UER', 'ABC', 'XYZ', 'EER')
['LastName'] = ('Smith', 'Vicente', 'Simpson', 'Thompson')
}
Sorted by Employee ID:
array
{
['Employee_ID'] = (0002, 1002, 1112, 4508)
['Business_Unit'] = ('XYZ', 'UER', 'EER', 'ABC')
['LastName'] = ('Simpson','Smith', 'Thompson', 'Vicente')
}
--
My original array is a database query output:
Array
(
[0] => Array
(
[Employee_ID] => 0000
[Supervisor_ID] => 00000
[Location_Descr] => somewhere
[Start_Date] => 06/03/2002
[Service_Date] => 06/03/2002
[Rehire_Date] => 00/00/00
[Business_Unit] => YYYY
[Job_Title] => Manager
[Email] => email#example.com
[Dept_Desc] => bla bla bla
[Employee_Name_LF] => Last, First
[Supervisor_Name_LF] => Last, First
[Term_Date] => 00/00/00
[Preferred_Name] => Someone
[Source] => Sheet2
)
)
There a several more rows.
The main purpose is to show the results as an HTML table and to generate a CSV file. I already made those functions using the modified structure (the first that I posted). I thought it would be easier to deal with that structure... Indeed it was, but not for sorting unfortunately.
The array_multisort documentation (http://php.net/manual/en/function.array-multisort.php) suggests separating each column as an individual array.. However, as you can see I have several columns (and the user can select more or less to be shown before performing the query.. So I can't just list all of them on the statement).
I a willing to change everything just to make the code better to be worked with.
Ugly - would be a lot easier if you formatted the input tables.
$arr = array(
'Employee_ID' => array('1002', '4508', '0002', '1112'),
'Business_Unit' => array('UER', 'ABC', 'XYZ', 'EER'),
'LastName' => array('Smith', 'Vicente', 'Simpson', 'Thompson')
);
$employees = array();
foreach (range(0, sizeof($arr[current(array_keys($arr))]) - 1) as $k) {
$emp = array();
foreach ($arr as $col => $vals) {
$emp[$col] = $arr[$col][$k];
}
$employees[] = $emp;
}
$sort = array();
foreach ($employees as $k => $v) {
$sort[$k] = $v['Employee_ID'];
}
array_multisort($sort, SORT_ASC, $employees);
print_r($employees);
And to put back in the original format:
$arr_sorted = array();
foreach (array_keys($arr) as $col) {
$arr_sorted[$col] = array();
foreach ($employees as $emp) {
$arr_sorted[$col][] = $emp[$col];
}
}
print_r($arr_sorted);
Thank you for posting the extra details in your question, as they did help in understanding the intent of your question.Now, you didn't tell us how that table should look; If you want the employees one per row, or one per column. Which is kind of crucial to know. Normally one would have one employee per line, especially if this is to be exported to CVS. However, I have a suspicion that it's the latter you want. Otherwise you've gone about this in a very overly complicated manner.Point in case: Normal one-per-row layout:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "e.employee_id, e.first_name, e.lastname, u.business_unit, s.email";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$query = <<<outSQL
SELECT {$Fields} FROM `unit` AS u
INNER JOIN `employee` AS e ON e.employee_id = u.unit_id
INNER JOIN `employee` AS s ON s.employee_id = u.supervisor_id
ORDER BY e.`employee_id`
outSQL;
$data = $db->query($query);
// Creating a printf() template for the output, to make the code easier to maintain.
$rowTemplate = <<<outHTML
<tr>
<td>%1\$d</td>
<td>%2\$s</td>
<td>%3\$s</td>
</tr>
outHTML;
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<thead>
<tr>
<th>ID</th>
<th>First name</th>
<th>Last name</th>
</tr>
</thead>
<tbody>
%s
</tbody>
</table>
outHTML;
// Regular table output, one employee per line.
$temp = '';
foreach ($data as $e) {
// hs() is a shortcut function to htmlspecialchars (), to prevent against XSS.
$temp .= sprintf($rowTemplate, $e['employee_id'], hs($e['first_name']), hs($e['lastname']));
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
If you want to do it one per column, it becomes a bit more intricate. Though, still a bit easier than your first attempt. :)
Namely, something like this:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "employee_id, first_name, lastname";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$data = $db->query("SELECT {$Fields} FROM `employees` ORDER BY `employee_id`");
// We need to know how many columns we'll have. One per employee.
$columns = count ($data);
// Rows have a header in front of each line, and one td tag for each employee.
$rowTemplate = "\t\t<th>%s</th>\n".str_repeat("\t\t\t<td>%s</td>\n", $columns);
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<tbody>
%s
</tbody>
</table>
outHTML;
// Reformat the array to give us the data per-column.
$temp = array ();
foreach ($data as $field => $e) {
// Since we've already sorted the data in the database we don't need to do any further sorting here.
// Also note that I'm doing the escaping here, seeing as this array will only be used for output.
$temp['Employee ID'][] = intval($e['employee_id']);
$temp['First name'][] = hs($e['first_name']);
$temp['Last name'][] = hs($e['lastname']);
}
// Now we do the same as in the above example.
$rows = '';
foreach ($temp as $label => $l) {
// We have the label as the first template variable to be added, so put it as the first element.
array_unshift($l, $label);
// Add the current row of items to the output, using the previously established template.
$rows = vprintf($rowTemplate, $l);
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
PS: Haven't tested the code, but it should work.
I ran into his problem and after much angst found a really nice solution in the notes on the php manual page - I now have the following function which i use whenever I need to solve this type of problem.
function fnArrayOrderby(){
//function to sort a database type array of rows by the values in one or more column
//source http://php.net/manual/en/function.array-multisort.php - user notes
//example of use -> $sorted = fnArrayOrderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
$args = func_get_args(); //Gets an array of the function's argument list (which can vary in length)
//echo "sorting ".$args[0]."<br>";
if (!isset($args[0])) { return;}
$data = array_shift($args); //Shift an element off the beginning of array
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}

How can I loop through an array while averaging the values of one element and only keep the newly averaged field in PHP?

I have database that contains scores which are stored daily. I want to average each months scores for each user. So far I have this:
DB structure:
id | name | tscore | added
int| string | float(100 or less)| date(2014-01-01 16:34:22)
Code:
while($row = mysql_fetch_assoc($getChartData)){ // Data from MySQL
$added_date = explode(' ',$row['added']); // Date formate 2014-01-01 16:34:22
$chartData[] = array(
'id' => $row['name'],
'tscore' => $row['tscore'],
'added' => $added_date[0] // Here I take the month only
);
}
if($_POST['range'] == 'month'){
foreach($chartData as $key => $value){
$added = explode('-',$chartData[$key]['added']);
$count = 1;
foreach($chartData as $key2 => $value2){
$added2 = explode('-',$chartData[$key2]['added']);
if($chartData[$key]['id'] === $chartData[$key2]['id'] && $added[1] === $added2[1]){ // if user is the same and the month is the same, add the scores together, increment counter, and unset 2nd instance
$chartData[$key]['tscore'] = ((float)$chartData[$key]['tscore'] + (float)$chartData[$key2]['tscore']);
$count++;
unset($chartData[$key2]);
}
}
$chartData[$key]['tscore'] = ($chartData[$key]['tscore']/$count); // Average all the scores for the month.
}
}
The problem is this method is deleting all the elements of the $chartData array. What can I try to resolve this?
You should try to solve it with MySQL. Try something like this (replace 'your_scores_table' with your table name):
SELECT
Score.name,
AVG(Score.tscore) AS `avg`,
CONCAT(YEAR(Score.added), '-', MONTH(Score.added)) AS `year_month`
FROM
your_scores_table AS Score
GROUP BY
Score.name ASC,
YEAR(Score.added) DESC,
MONTH(Score.added) DESC
;
Your logic is wrong. You are looping through the same array twice. Which means that the following if will always evaluate to true which means that array item will always get unset
//This will always be true
if($chartData[$key]['id'] === $chartData[$key2]['id'] && $added[1] === $added2[1]){
It may be simpler for you to create another array where you keep your scores. Something like
$aScores = array();
$count = 1;
foreach($chartData as $key => $value){
//Add score to a different array
$aScores[$value['name']]['tscore'] = (($aScores[$value['name']]['tscore'] + $value['tscore']) / $count);
$count++;
}
Also I would look into the MySQL AVG function. You could use that to save you having to do it in PHP

Count unique value from associative array

First, thanks for any help.
I've spent countless hours on here and other forums trying to find my exact solution but either 1) I'm not understanding the one's I've read or 2)I haven't found the right answer.
In PHP, I've run a somewhat complex query which returns a set of records similar to:
id | name | direction|
1 aaa east
2 bbb west
3 ccc east
I've created an associative array such as:
$query=("select * from foo");
$result=mysql_query($query);
$array=mysql_fetch_assoc($result);
Now, what I need to do seems simple but I'm not grasping the concept for some reason.
I need to loop through the entire $array and return a count of any value that I want to specify and store that count in a variable.
i.e. Show me how many times east shows up in the "direction" column and put that in a variable called $eastcount.
I've tried various combinations of using foreach loops with incremental counts and have tried using array_count_values but have not been able to put the pieces together :/
// build query
$query=("select * from foo");
// execute query
$result=mysql_query($query);
// declare vars
$east_count = 0;
// iterate through results
while ($data = mysql_fetch_array($result)) {
// grab DIRECTION column value
$direction = $data['direction'];
// detect 'east'
if ($direction == 'east') {
// increment 'east' count
$east_count++;
}
}
// print # of times we had 'east'
echo("direction said 'east' $east_count times");
This should work (sorry for the lack of code block I'm on my iPhone).
http://www.php.net/manual/en/function.array-count-values.php
$array = array(1, "hello", 1, "world", "hello");
print_r(array_count_values($array));
Array
(
[1] => 2
[hello] => 2
[world] => 1
)
How about this:
query=("select * from foo");
$result=mysql_query($query);
$directions = array();
while($direction = mysql_fetch_assoc($result) {
$directions[] = $direction['direction'];
}
$directionCounts = array_count_values($directions);
//now you can access your counts like this:
echo $directionCounts['east'];
First, of all you should be using mysqli instead. But, anyhow I hope this makes some sense.
if ($result) {
$count = 0;
while ( $row = mysql_fetch_assoc($result)) {
if ($row["route"] === "east") {
$count += 1;
}
}
return $count;
}

Categories