3 Dimensional Associative Array to HTML table - php

This is what my array looks like.
(int) Year 1 => array(
'Department 1' => array(
'Sales' => '12345'
),
'Department 2' => array(
'Sales' => '12345'
),
),
(int) Year 2 => array(
'Department 1' => array(
'Sales' => '12345'
),
'Department 2' => array(
'Sales' => '12345'
),
)
I want to be able to create a table where the headers are the Years on the X axis.
The Y axis needs to start with the Department name. The adjoining cells need to have sales, revenue, and total in one cell.
It should look like this...
Department____| ___YEAR1_______ | __Year2
Department 1 |Sales [dept 1][year 1] | Sales[dept 1][year 2]
Department 2 |Sales [dept 2][year 1] | Sales [dept 2][year 2]
I used nested foreach loops
foreach($List as $key=>$row) {
echo "<tr><td>".$key."</td>";
foreach($row as $key2=>$col){
echo "<td>" . 'Sales: '.round($col['sales'],2) ."</td>";
}
echo "</tr>";
}
echo "</table>"; ?>
but it printed the table with departments names on top on the x axis and years on the y axis. How do I get years on the x axis and departments on the y axis.

The problem is that the dimensions of your array don't correspond with the order that you want to iterate through them for your table. You need to pull out the keys explicitly to iterate through them in the nested loops.
$years = array_keys($List);
// Print column headings
echo "<table><thead><tr><th>Department</th>";
foreach ($years as $year) {
echo "<th>$year</th>";
}
echo "</tr></thead>";
// Print data rows
echo "<tbody>"
foreach (array_keys($List[$years[0]]) as $dept) {
echo "<tr><th>$dept</th>";
foreach ($years as $year) {
echo "<td>{$List[$year][$dept]['Sales'}]</td>";
}
echo "</tr>";
}
echo "</tbody></table>";
As I mentioned, this depends on all years having the same departments. If you add new departments over time, it won't work. You can fix this by using array_reduce to merge all the department lists, I'll leave that as an exercise for the reader.

Related

Show closest release date titles using foreach-array in PHP

I'm working on a game release section, where I display games that are about to release. I only work with game information, and a release date.
My array looks like this (actual array has a lot more info so this is just a replicate):
$arr = [
[
'id' => 'UP0006-CUSA08724_00-BATTLEFIELDV0000',
'attributes' => [
'name' => 'Battlefield V [test1]',
'thumbnail-url-base' => 'https://store.playstation.com/store/api/chihiro/00_09_000/container/US/en/999/UP0006-CUSA08724_00-BATTLEFIELDV0000/1539651459000/image'
'release-date' => '2018-12-14T00:00:00Z'
],
],
[
'id' => 'UP0006-CUSA08724_00-BATTLEFIELDV0000',
'attributes' => [
'name' => 'Battlefield V [test2]',
'thumbnail-url-base' => 'https://store.playstation.com/store/api/chihiro/00_09_000/container/US/en/999/UP0006-CUSA08724_00-BATTLEFIELDV0000/1539651459000/image'
'release-date' => '2018-10-14T00:00:00Z'
],
],
[
'id' => 'UP0006-CUSA08724_00-BATTLEFIELDV0000',
'attributes' => [
'name' => 'Battlefield V [test3]',
'thumbnail-url-base' => 'https://store.playstation.com/store/api/chihiro/00_09_000/container/US/en/999/UP0006-CUSA08724_00-BATTLEFIELDV0000/1539651459000/image'
'release-date' => '2019-10-14T00:00:00Z'
],
],
];
I want to display the game titles that are closest to release to the current date such as [test1], and skip the ones that have been released already such as [test2].
I've tried to skip them using this line:
if (strtotime(date('Y-m-d H:i:s')) > strtotime($title['attributes']['release-date'])) continue;
But for some reason it does not seem to skip them, and just keeps them in.
Also I have no idea where to start when trying to show the game titles that are closest to release to the current date.
My full code:
foreach($json['included'] as $key => $title) {
$cusa = substr(explode('-', $title['id'], 3)[1], 0, -3);
if($title['type'] == 'game' && substr($cusa, 0, 4) == 'CUSA') {
// if the day of release has already passed, skip
if (strtotime(date('Y-m-d H:i:s')) > strtotime($title['attributes']['release-date'])) continue;
?>
<div class="game-banner" style="background:url(<?php echo $title['attributes']['thumbnail-url-base']; ?>)">
<h4 class="psplus-game-name"><?php echo $title['attributes']['name']; ?></h4>
</div>
<?php
if($key >= 4) break; // display only 3
}
}
}
You just need to calculate the seconds left to release date, and if it's a positive number echo it.
foreach($arr as $game){
$timeleft = strtotime($game['attributes']['release-date'])-time();
if($timeleft>0) echo floor($timeleft/86400) ." days left to ".$game['attributes']['name'] ." \n";
}
//58 days left to Battlefield V [test1]
//362 days left to Battlefield V [test3]
https://3v4l.org/OMetR
If your initial array is unsorted and you want then sorted you can add them to an array with key being the timeleft and sort on keys with ksort().
foreach($arr as $game){
$timeleft = strtotime($game['attributes']['release-date'])-time();
if($timeleft>0) $games[$timeleft] = floor($timeleft/86400) ." days left to ".$game['attributes']['name'] ." \n";
}
ksort($games);
echo implode("", $games);
https://3v4l.org/gbLCs

PHP joining row from database

I need an advice how to display data from array (result of sql query) in PHP.
Here's the problem:
My query result is 2 row (top figure). Currently, I'm using foreach method to display all data, thus, the foreach will iterate 2 times, right?
Now, I want to ask:
In my web page, how I can display like the bottom figure??
How to join the second row (the theory's score is 0, and the lab's score is 75 and 80) to the first row? So it'll be ONLY 1 row for ID 112.
EDIT:
The SQL query is not my part. I've just received that data (top figure), and my job only to display it to web page.
Well as you used to display rows with foreach you could do it the same way:
* create new array
* loop through your current array
* save to new array by ID and do SUMs
* you can do output from newly created array.
create new array by loop through your current array which will filter out 0 values probably by using array_walk_recursive() or array_map() or array_filter()
then at this stage you got filtered array
you can do output from filtered array
I'm wondering why you have two rows with same 'id'. Usually 'id' should be the primary key...
Anyway, you could simply combine the rows with same 'id', adding the equally named fields casting them like integers.
EDIT 1-2:
Supposing code is in associative arrays:
$rows = array(
0 => array(
'id' => 112,
'theory' => array('score1' => 70, 'score2' => 80),
'lab' => array('score1' => 0, 'score2' => 0)
),
1 => array(
'id' => 112,
'theory' => array('score1' => 0, 'score2' => 0),
'lab' => array('score1' => 75, 'score2' => 80)
),
2 => array(
'id' => 110,
'theory' => array('score1' => 0, 'score2' => 0),
'lab' => array('score1' => 75, 'score2' => 80)
)
);
// New buffer for data
$newArray = array();
// Loop to combine buffer
foreach ($rows as $row) {
if (array_key_exists($row['id'], $newArray))
{
$newArray[$row['id']]['theory']['score1'] += $row['theory']['score1'];
$newArray[$row['id']]['theory']['score2'] += $row['theory']['score2'];
$newArray[$row['id']]['lab']['score1'] += $row['lab']['score1'];
$newArray[$row['id']]['lab']['score2'] += $row['lab']['score2'];
} else {
$newArray[$row['id']]['theory']['score1'] = $row['theory']['score1'];
$newArray[$row['id']]['theory']['score2'] = $row['theory']['score2'];
$newArray[$row['id']]['lab']['score1'] = $row['lab']['score1'];
$newArray[$row['id']]['lab']['score2'] = $row['lab']['score2'];
}
}
// Loop to show data
foreach ($newArray as $key => $value) {
echo $key." ".$value['theory']['score1']." ".$value['theory']['score2']." ".$value['lab']['score1']." ".$value['lab']['score2']."\n";
}
Output:
112 70 80 75 80
110 0 0 75 80
Let's say that you receive your data as Arrays:
$data=array();
$data[0]=[112,70,80,0,0];
$data[1]=[112,0,0,75,80];
$data[2]=[113,71,81,0,0];
$data[3]=[113,0,0,76,81];
If you know in advance that each ID will have exactly two records:
echo '<table>';
echo '<thead>';
echo '<tr>';
echo '<th rowspan="2">ID</th><th colspan="2">theory</th><th colspan="2">lab</th>';
echo '</tr>';
echo '<tr>';
echo '<th>score1</th><th>score2</th><th>score1</th><th>score2</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
for($i=0;$i<count($data);$i++)
{
$d=$data[$i];
echo '<tr>';
echo '<td>'.$d[0].'</td>'; //ID
echo '<td>'.$d[1].'</td><td>'.$d[2].'</td>';
$d=$data[++$i]; //take next element from array
echo '<td>'.$d[3].'</td><td>'.$d[4].'</td>';
echo '</tr>';
}
echo '</tbody>';
echo '</table>';
Code on PHPfiddle.
But generally, your SQL query should be changed in order to represent pivoted data and then you will not have this issue. However, you emphasized that this is out of your power.

check if value exist in each array multidimensional array

i hava multidimensional array
<?php
$data = array(
array(
'name'=>'ahmed',
'job'=>'engineer',
'age'=>25,
'hobbies' => array('drawing','swimming','reading'),
'skills' => array('coding','fasting learning','teaching')
),
array(
'name'=>'Sara',
'job'=>'designer',
'age'=>19,
'skills'=>array('fast learning')
) ,
array(
'name'=>'Ali',
'age'=>25,
'city'=>'cairo'
),
array(
'name'=>'Hossam',
'job'=>'accountant',
'age'=>25,
'city'=>'zagazig'
),
array(
'name'=>'Esraa',
'job'=>'Designer',
'age'=>23,
'city'=>'zagazig',
'hobbies' => array('writing','reading'),
'skills' => array('coding','teaching')
),
);
i want count Arrays where city = "zagazig" or "cairo"
and echo Array Values
Example :
There is [ 1 ] people of City => [ cairo ] :
---------------- Result -----------------------
Name => Ali
Age => 25
City => cairo
if City !exist echo Values
Example :
*---------------- Invaild Data -------------
----------------------- First ---------------
Name => Sara
Job => designer
Age => 19
Skill => fast learning
----------------- Second ----------------
Name => ahmed
Job => engineer
Age => 25
-------------------- Hobbies ----------------
drawing
swimming
reading
-------------------- Skills ----------------
coding
fasting learning
teaching
but i don't know how to loop Multidimensional Array
Given that this is just a raw array, a simple if with foreach should suffice.
First, if the criteria is to get certain entries using city, just use a stripos to search;
$search_string = 'zagazig';
$results = array();
foreach($data as $value) {
if(
!empty($value['city']) &&
(stripos($value['city'], $search_string) !== false)
) {
$results[] = $value;
}
}
This checks if the entry has a city index, then just pushes that array inside a container $result. After gathering the results, just loop it like any normal array:
if(!empty($results)) {
echo 'Number of results: ' , count($results), '<br/> Result <hr/>';
foreach($results as $r) {
echo "
Name: {$r['name']}
Job: {$r['job']}
Age: {$r['age']} <br/>
";
echo !empty($r['hobbies']) ? '<br/>Hobbies: <br/>' . implode('<br/>', $r['hobbies']) : '';
}
}
Output
Of course you can use a <table> tag if you want, this is just an ugly example.
If you like something a little bit different, you can also use array_filter:
Here's an example of it (this also includes some searching inside hobbies and skills):
$search_string = 'coding';
$criteria = 'skills';
$results = array_filter($data, function($e) use ($search_string, $criteria) {
return (
!empty($e[$criteria]) &&
(!is_array($e[$criteria])
? (strpos($e[$criteria], $search_string) !== false)
: (in_array($search_string, $e[$criteria]))
)
);
});
Output
Use php foreach() like:
foreach (array_expression as $value)
{
statement
}
Foreach Documentation

how to display checkin table in one row

I have a table that looks like this.
pers_id pers_name pers_date pers_date_attend_ind
431 Bacon 1/14/2013 N
431 Bacon 1/27/2013 N
431 Bacon 1/28/2013 N
431 Bacon 2/17/2013 N
I'd like to display it in php like
<date 1> <date 2> <Date 3>
Bacon N N N
I'm at a loss for how to do that.
Assume your $rows variable will looks after fetching results like this:
$rows = array(0 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '1/14/2013', 'pers_date_attend_ind' => 'N'),
1 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '1/27/2013', 'pers_date_attend_ind' => 'N'),
2 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '1/28/2013', 'pers_date_attend_ind' => 'N'),
3 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '2/17/2013', 'pers_date_attend_ind' => 'N'),
);
Then I played with this array to make it look like this:
Array
(
[431] => Array
(
[name] => Bacon
[dates] => Array
(
[1/14/2013] => N
[1/27/2013] => N
[1/28/2013] => N
[2/17/2013] => N
)
)
)
using foreach loop:
foreach($rows as $value)
{
$array[$value['pers_id']]['name'] = $value['pers_name'];
$array[$value['pers_id']]['dates'][$value['pers_date']] = $value['pers_date_attend_ind'];
}
Now it looks much better for your table(s) preparation. I created a function what returns a table(s) as you set in your question based on this modified array.
function generate_table($array)
{
$html = '';
foreach($array as $value)
{
$html .= '<table>'; // start table inside the loop. It will looks better due to each member may have different number of date count.
$html .= '<tr>';
$html .= '<td> </td>';
foreach($value['dates'] as $k => $v)
{
$html .= '<td>' . $k . '</td>';
}
$html .= '</tr>';
$html .= '<tr>';
$html .= '<td>' . $value['name'] . '</td>';
foreach($value['dates'] as $v)
{
$html .= '<td>' . $v . '</td>';
}
$html .= '</tr>';
$html .= '</table>';
}
return $html;
}
This function looks a bit nasty, but it works. It's on you to improve this function if you want.
Live previews
Preview for single user
Preview for multiple users
Preview of result
What you want is a simple SELECT query to get all pers_date and pers_date_attend_ind for one person and limit it to three results only.
SELECT `pers_date`, `pers_date_attend_ind` FROM `table` WHERE `pers_id` = 431 ORDER BY `pers_date` DESC LIMIT 3
Then just fetch the results and print them with php.
Unfotunately mysql doesn have magic function to transform values wich are variables to column names , But in your case you should have an extra column (date_number i have added it in demo) which count the number of dates added.
here is aproach to it:
select `pers_name`,
max(case when `date_number` = 1 then `pers_date_attend_ind` end) as date1,
max(case when `date_number` = 2 then `pers_date_attend_ind` end) as date2,
max(case when `date_number` = 3 then `pers_date_attend_ind` end) as date3,
max(case when `date_number` = 4 then `pers_date_attend_ind` end) as date4
from Table1
HERE demo to play with

html output logic from array

My data comes from a database, and has been grouped by day_id, so the array is sorted by day_id.
Code + sample output provided, kind of hard to put in words.
I got my inspiration so far from this accepted answer, but I need a slight adjustment.
$array = array(
0 => array(
'id' => '5',
'day_id' => '1',
'Foo' => array(
'id' => '28',
'name' => 'My day_id is 1'
)
),
1 => array(
'id' => '6',
'day_id' => '1',
'Foo' => array(
'id' => '29',
'name' => 'My day_id is 1'
)
),
2 => array(
'id' => '7',
'day_id' => '2',
'Foo' => array(
'id' => '30',
'name' => 'My day_id is 2'
)
),
3 => array(
'id' => '8',
'day_id' => '3',
'Foo' => array(
'id' => '31',
'name' => 'My day_is 3'
)
)
);
And my code to output it:
$day = 0;
foreach($array as $a) {
// $a['day_id'] = 1, condition is true. output header once.
if($day != $a['day_id']) {
echo '<h3>The Day is ' . $a['day_id'] . '</h3>' . "\n";
}
// output the elements Foo key content.
echo $a['Foo']['name'] . "\n";
// store the current value to compare on the next iteration
// $a['day_id'] will eventually be 2, causing the condition to fire again.
$day = $a['day_id'];
}
This outputs:
<h3>The Day is 1</h3>
My day_id is 1
My day_id is 1
<h3>The Day is 2</h3>
My day_id is 2
<h3>The Day is 3</h3>
My day_is 3
I now want to wrap each "Day" in a DIV, but I cannot figure out the logic. If I replace the <h3> with an open div, I do not know where to put the closing </div>. My attempts thus far have just led to each day having an open div, but not a closed one so they are nested, rather than separate.
I can't put the </div><div class="day-X"> as there will be an extra </div> at the start which would break the layout.
Desired output:
<div class="day-1">
<h3>The Day is 1</h3>
My day_id is 1
My day_id is 1
</div>
<div class="day-2">
<h3>The Day is 2</h3>
My day_id is 2
</div>
<div class="day-3">
<h3>The Day is 3</h3>
My day_is 3
</div>
Hope this makes sense - thanks
You will need to loop twice, one for the days and one for the items that has this day. Without using any other SQL queries you will need to store the days in an array first. then you could loop the days and for each day you will echo the <div> and the day header, at the end you will echo the </div>.
inside the foreach you can loop again using the same array to check each item if it's has the same day or not. if yes then echo the name of the item, otherwise don't do anything.
I have tested this code, you can check it and let me know if you are having any problems with it.
foreach($array as $day){
$days[] = $day['day_id']; // store all the days in an array
}
// now days[] has [1,1,2,3]
$days = array_unique($days); // get unique days only no duplicated
//now days[] has [1,2,3]
foreach($days as $d){ // for each day
echo '<div class = "day-'.$d.'">';
echo '<h3>The Day is ' . $d . '</h3>' . "\n";
foreach($array as $a) { // check all other items if the item has the same day then echo
if($a['day_id'] == $d){
echo $a['Foo']['name'] . "\n";
}
}
echo '</div>';
}
Output:
<div class = "day-1">
<h3>The Day is 1</h3>
My day_id is 1
My day_id is 1
</div>
<div class = "day-2">
<h3>The Day is 2</h3>
My day_id is 2
</div>
<div class = "day-3">
<h3>The Day is 3</h3>
My day_is 3
</div>

Categories