Hello I got a question: I want to make a table of these two arrays. In the first column I want the players name, second column the score and the third column the average of the score. I only get the players in the table and it is repeating itself. I dont know how to make it work. I know the value in the foreach is the players so I knew it would repeat itself but how can I fix this?
<?php
$aScore = array (1 => 0, 2 => 20, 3 => 4, 4 => 23, 5 => 5, 6 => 4);
$aPlayers = array (1 => 'Jansen', 2 => 'Boularus', 3 => 'Rintintin', 4 => 'Chavez', 5 => 'Zomers', 6 => 'Tahamata');
echo '<table border="1">';
echo '<tr><td>Player</td><td>Score</td><td>Average score</td></tr>';
foreach($aPlayer as $key => $value)
{
echo '<tr><td>'.$value.'</td><td>'.$value.'</td><td>'.$value.'</td></tr>';
};
echo '</table>';
?>
Just try with:
foreach($aPlayers as $key => $value)
{
echo '<tr><td>'.$value.'</td><td>'. $aScore[$key] .'</td><td>'. $aAverageScore[$key] .'</td></tr>';
}
There is no $aAverageScore variable in your question but I assume that you will know what to put here instead.
However you should store your data in multidimentional associative array, like:
$players = array(
array(
'name' => 'Jansen',
'score' => 0,
'average' => 0
),
array(
'name' => 'Boularus',
'score' => 20,
'average' => 20
),
// ...
);
And loop it with:
foreach ($players as $player) {
echo '<tr><td>' . $player['name'] . '</td><td>' . $player['score'] . '</td><td>' . $player['average'] . '</td></tr>';
}
Use a simple for loop instead of a foreach:
for ($k=1; $k<=count($aPlayer); $k++) {
echo '<tr><td>'.$aPlayer[$k].'</td><td>'.$aScore[$k].'</td><td></td></tr>';
}
Related
Consider the following $data array:
Array
(
[0] => Array
(
[code] => 20
[name] => Name 1
[month] => 4
[cost] => 100
..
..
)
[1] => Array
(
[code] => 30
[name] => Name 2
[month] => 3
[cost] => 120
..
..
)
[1] => Array
(
[code] => 30
[name] => Name 2
[month] => 6
[cost] => 180
..
..
)
..
..
)
Each array can have unknown number of codes. Each code has a different month ID. I want to sort and display the data so that there is just one row for the each code, and then in that row, display the value of the [cost] in the column number equal to the month. For example:
Column 1 2 3 4 5 6 7 8 9 10 11 12
Name 1 100
Name 2 120 180
Here's what I'm trying:
In order to find out how many rows should be printed, I fetch the unique code values:
$codes = array();
foreach( $data as $row ){
if ( in_array($row['code'], $codes) ) {
continue;
}
$codes[] = $row['code'];
}
Next, I use a loop to print the rows:
foreach( $codes as $code ){
//print 12 columns for each othe row
for ($i = 1; $<=12; $i++) {
//display column value if the code is same as the row
//and the month value is same as $i
//here's the problem
if (( $data['code'] == $code ) &&( $data['month'] == $i )) {
echo $data['cost'];
}
}
}
Problem/Question:
Do I need to put another loop inside the for loop to check if the $data['code'] == $code ? Or how can I do that?
I would use one loop to re-index the array:
$list = $codes = [];
for ($array as $item){
$list[$item['code']][$item['month']] = $item;
$codes[$item['code']] = $item['name'];
}
then use two loops to print:
for ($codes as $code => $codeName){
echo '<tr><th>', $codeName, '</th>';
for (range(1, 12) as $month){
echo '<td>', ($list[$code][$month]['cost'] ?? ''), '</td>;
}
echo '</tr>', "\n";
}
I really do not like the idea of if()s inside the loops.
I would suggest that you preprocess your data to a structured array first and then you print it, for example, indexed by code with a structure like:
[
['the code'] => [
'name' => '',
'months' => [
'6' => // cost
]
]
]
You can do it like this:
$items = [
[
'code' => 20,
'name' => 'Name 1',
'month' => 4,
'cost' => 100,
],
[
'code' => 30,
'name' => 'Name 2',
'month' => 3,
'cost' => 120,
],
[
'code' => 30,
'name' => 'Name 2',
'month' => 6,
'cost' => 180,
],
];
$sortedItems = [];
foreach ($items as $item) {
if (!isset($sortedItems[$item['code']])) {
$sortedItems[$item['code']] = [
'name' => $item['name'],
'months' => [],
];
}
$sortedItems[$item['code']]['months'][$item['month']] = $item['cost'];
}
You can the print it using a function similar to this:
function printItemsOf(array $list) {
echo '<table>';
// print header
echo '<tr>';
echo '<td>Column</td>';
for ($i = 1; $i <= 12; $i++) {
echo '<td>' . $i . '</td>';
}
echo '</tr>';
// print items
foreach ($list as $code => $item) {
echo '<tr>';
echo '<td>' . $item['name'] . '</td>';
for ($i = 1; $i <= 12; $i++) {
if (!isset($item['months'][$i])) {
echo '<td></td>';
} else {
echo '<td>' . $item['months'][$i] . '</td>';
}
}
echo '</tr>';
}
echo '</table>';
}
Which outputs:
<table border="1"><tr><td>Column</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td></tr><tr><td>Name 1</td><td></td><td></td><td></td><td>100</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>Name 2</td><td></td><td></td><td>120</td><td></td><td></td><td>180</td><td></td><td></td><td></td><td></td><td></td><td></td></tr></table>
I have been researching comparing two associative arrays, which I have only been able to do with a fair degree of accuracy. I have read all similar threads on S.O. but none have solved or addressed the issue I am having, which is, while comparing two associative arrays the test data will successfully show the appropriate matches, however when I attempt to count the number of matched values, I am getting some strange results.
EDIT:
<?php
$data = array(
'Alpha' => array(
'peace' => 0,
'art' => 1,
'trend' => 0,
'night' => 1,
'shop' => 0
),
'Beta' => array(
'peace' => 1,
'art' => 1,
'trend' => 1,
'night' => 1,
'shop' => 0
),
'Gamma' => array(
'peace' => 0,
'art' => 1,
'trend' => 1,
'night' => 1,
'shop' => 0
)
);
$choices = array(
'peace' => 0,
'art' => 1,
'trend' => 0,
'night' => 1,
'shop' => 0
);
function compare($data, $choices)
{
foreach ($data as $city => $name)
{
echo $city . '<br>';
foreach ($name as $key => $value)
{
($choices[$key] === $value) ? $match = 'match' : $match = 'no';
($choices[$key] === $value) ? $i++ : $i = 0;
echo $key . ':' . $value . ':' . $choices[$key] . ':' . $match . '<br>';
}
echo 'Matches:' . $i . '<br><br>';
}
}
compare($data, $choices);
?>
OUTPUT DATA
Format of data is as follows
-----------------------------
name of key:$data value:$choices value:is match
Alpha
peace:0:0:match
art:1:1:match
trend:0:0:match
night:1:1:match
shop:0:0:match
Matches:5
Beta
peace:1:0:no
art:1:1:match
trend:1:0:no
night:1:1:match
shop:0:0:match
Matches:2
Gamma
peace:0:0:match
art:1:1:match
trend:1:0:no
night:1:1:match
shop:0:0:match
Matches:2
'Alpha' should return 5 matches, which it does.
'Beta' should return 3, it returns 2.
'Gamma' should return 4, it returns 2.
Any help would be greatly appreciated. Thank you in advance.
The problem is how you are incrementing the count with a ternary statement. When you do
($choices[$key] === $value) ? $i++ : $i = 0;
It will reset $i to zero any time it encounters a non-match.
Using a simple conditional instead should give you the correct count.
if ($choices[$key] === $value) $i++;
You can initialize $i to 0 before the inner foreach loop.
I have two foreach loops like below.
The idea is to process type 2 before type 1 in order. Code below works just fine but I was wondering how can I use unset to achieve same result instead of using another array $processed to keep track of what was processed.
I know that PHP foreach clones/copies the $data array for iteration. In other words, is it possible to unset type 2 from $data in second foreach loop and somehow first foreach loop skip them?
I know that PHP foreach clones/copies array for iteration.
$data = array(
array('type' => 1),
array('type' => 2),
array('type' => 2),
array('type' => 2),
array('type' => 1),
array('type' => 2),
array('type' => 2),
);
$processed = array();
foreach ($data as $firstKey => $firstValue) {
if (in_array($firstKey, $processed)) {
continue;
}
foreach ($data as $secondKey => $secondValue) {
if ($secondValue['type'] == 2) {
echo $secondValue['type'] . " processed " . "<br/>";
$processed[] = $secondKey; // can I use unset here?
}
}
echo $firstValue['type'] . " processed" . "<br/>";
}
Update
Hopefully with this update I can get my intention out.
Each child has a reference to its parent. All children need to be processed before its parent. Code below should work just fine. you can try it and the output of code below is the desired behavior. I would like to do it with unset if possible.
$data = array(
array('id' => 1, 'ref' => null, 'name' => 'parent 1'),
array('id' => 2, 'ref' => 1, 'name' => 'child 1'),
array('id' => 3, 'ref' => 1, 'name' => 'child 2'),
array('id' => 4, 'ref' => 1, 'name' => 'child 3'),
array('id' => 5, 'ref' => null, 'name' => 'parent 2'),
array('id' => 6, 'ref' => 5, 'name' => 'child 1'),
array('id' => 7, 'ref' => 5, 'name' => 'child 2'),
array('id' => 8, 'ref' => null, 'name' => 'parent 3'),
array('id' => 9, 'ref' => 8, 'name' => 'child 1'),
array('id' => 10, 'ref' => 8, 'name' => 'child 2'),
);
$processed = array();
foreach ($data as $ref => $firstValue) {
if (in_array($ref, $processed)) {
continue;
}
foreach ($data as $secondKey => $secondValue) {
if ($secondValue['ref'] == $firstValue['id']) {
echo $secondValue['id'] . "- " . $secondValue['name'] . " processed " . "<br/>";
$processed[] = $secondKey;
}
}
echo $firstValue['id'] . "- " . $firstValue['name'] . " processed" . "<br/>";
echo "<hr/>";
}
Code above output:
2- child 1 processed
3- child 2 processed
4- child 3 processed
1- parent 1 processed
6- child 1 processed
7- child 2 processed
5- parent 2 processed
9- child 1 processed
10- child 2 processed
8- parent 3 processed
Here's a simpler version that doesn't require unsetting anything. It just tests the type. For each type 1 entry, it processes all the type 2 entries first, then processes that type 1 entry.
<?php
$data = array(
array('type' => 1),
array('type' => 2),
array('type' => 2),
array('type' => 2),
array('type' => 1),
array('type' => 2),
array('type' => 2),
);
foreach ($data as $firstKey => $firstValue) {
if ($firstValue['type'] == 1) {
foreach ($data as $secondKey => $secondValue) {
if ($secondValue['type'] == 2) {
echo $secondValue['type'] . " processed " . "<br/>";
}
}
echo $firstValue['type'] . " processed" . "<br/>";
}
}
Another way to do this, that doesn't require testing the types in the inner loops, is simply to make two arrays: $dataType1 contains all the type 1 entries in $data, and $dataType2 contains all the type 2 entries. Then you just use simple nested loops:
foreach ($dataType1 as $firstValue) {
foreach ($dataType2 as $secondValue) {
echo $secondValue['type'] . " processed " . "<br/>";
}
echo $firstValue['type'] . " processed" . "<br/>";
}
Redoing my answer to match up with the OP's updated question.
Here is one method of achieving similar output using a recursive function
function processData(&$data, $ref = null)
{
foreach ($data as $key => $value) {
if ($ref !== null && $value['ref'] !== $ref) {
continue;
}
$data = processData($data, $value['id']);
echo $value['id'] . "- " . $value['name'] . " processed" . "<br/>";
unset($data[$key]);
}
return $data;
}
processData($data);
This function will modify your array though, constantly unsetting elements as it works through it.
I am attempting to print out a table of the PHP multi-dimensional associative arrays. There are arrays for the class, assignments, students, scores.
I am familiar with MySQL queries, but I am not sure how to print out the table from a PHP multi-dimensional associative arrays. My thought process to access the score for the students' assignments for the class is similar to MySQL, but I know that doesn't work here. For a one dimensional, seems simple enough, but a multi-dimensional nested associative arrays I am not sure how to approach this?
Thanks in advance!
<?php
ini_set('display_errors', 'on');
$class=array (
'cat' =>
array (
2 =>
array (
'num' => '3',
'name' => 'Homework',
),
),
'assignments' =>
4 =>
array (
'clid' => '5000001001388',
'assnid' => '1',
'cat' => '3',
'due' => '20100802',
'points' => '5',
'title' => 'American Revolution',
),
),
'students' =>
array (
3 =>
array (
'stuid' => '460798', // stuid is the student's unique alphanumberic ID string
'num' => '4',
'first' => 'Thomas',
'last' => 'Jefferson',
'grade' => 'A', // these are summary statistics for the student for the class
'percent' => '94.7', // these are summary statistics for the student for the class
),
),
'scores' =>
array (
0 =>
array (
'assnid' => '1', // corresponds to assignment's 'assnid'
'stuid' => '460798', // corresponds to student's 'stuid'
'score' => '0', // this is the student's score
),
),
);
// display class properties
print($class["clid"]."<br>");
// display all class properties
foreach ($class["clid"] == $class["assignments"].["clid"] == $class["students"].["assnid"] as $property=>$value) {
print($property . " is " . $value . "<br>");
}
?>
So I used foreach to loop through students, assignments, and scores. I don't know if there's a better way of doing it.
echo <<<END
<body>
<table>
<thead>
<tr><th colspan="5" id="title">US History 2012</th></tr>
<tr>
<th>Students</th>
<th>ID</th>
<th>Grade</th>
<th>Percentage</th>
<th>American Revolution</th>
</tr>
</thead>
<tbody>
END;
foreach ($class["students"] as $students){
echo '<tr class="items">';
echo '<td>'.$students["first"].' '.$students["last"].'</td>';
echo '<td>'.$students["stuid"].'</td>';
echo '<td class="grade">'.$students["grade"].'</td>';
echo '<td class="perc">'.$students["percent"].'%</td>';
$i = 0;
$score4Avg = 0;
foreach ($class["assignments"] as $assignments){
foreach ($class["scores"] as $scores){
if ($scores["stuid"] == $students["stuid"] &&
$scores["assnid"] == $assignments["assnid"]){
echo '<td><input type="text" class="score'.$i.'" value="'.$scores["score"].'" onblur="recalculate();" tabindex="-1"></td>';
$i++;
}
if ($scores["assnid"] == $assignments["assnid"] &&
$assignments["title"] == "American Revolution"){
$score4Avg += $scores["score"];
}
}
}
echo '</tr>';
}
I need to create and populate a table with a array... for now with some help from the bloggers goes like this:
<?php
$details = array(
1 => array(
1 => 1000,
2 => 'Company A',
3 => '2014-05-10',
4 => '10:00:00',
5 => '15:00:00',
),
2 => array(
1 => 2000,
2 => 'Company A',
3 => '2014-05-11',
4 => '10:00:00',
5 => '15:00:00',
),
3 => array(
1 => 3000,
2 => 'Company B',
3 => '2014-05-10',
4 => '10:00:00',
5 => '15:00:00',
),
4 => array(
1 => 4000,
2 => 'Company B',
3 => '2014-05-11',
4 => '16:00:00',
5 => '19:00:00',
)
);
// Format our data into something we can use more easily
$flight_dates = array();
$times = array();
$dates = array();
foreach ($details as $flight_details) {
$company_name = $flight_details[2];
$date = $flight_details[3];
$time = $flight_details[4] . ' - ' . $flight_details[5];
// Keep a unique record of each date, and the times of flights
$dates[$date] = 1;
$times[$time] = 1;
// Record which date/time each company is flying
$flight_dates[$date][$time][] = $company_name;
}
// Create the table header
$html = '<table border="1">';
$html .= '<thead>';
$html .= '<tr>';
$html .= '<th> </th>';
foreach ($dates as $date => $value1) {
$html .= '<th>' . $date . '</th>';
}
$html .= '</tr>';
// Create the rows in the table
foreach ($times as $time => $value1) { // Loop through each flight time
$html .= '<tr>';
$html .= '<td>' . $time . '</td>'; // The first column is always the time
foreach ($dates as $date => $value2) { // Loop through each date
if (!empty($flight_dates[$date][$time])) { // Check if flights exist at the current time
$html .= '<td>' . implode(', ', $flight_dates[$date][$time]) . '</td>'; // List companies
} else { // No flights
$html .= '<td> </td>'; // Leave cell blank
}
}
$html .= '</tr>';
}
$html .= '</table>';
echo $html;
?>
The result is this:
|....................|.. 2014-05-10 ........| 2014-05-11|
|10:00:00 - 15:00:00 | Company A, Company B | Company A |
|16:00:00 - 19:00:00 |......................| Company B |
I'm looking to get this:
|....................|2014-05-10 | 2014-05-11|
|10:00:00 - 15:00:00 | Company A | Company A |
|10:00:00 - 15:00:00 | Company B |...........|
|16:00:00 - 19:00:00 |...........| Company B |
In my idea the deal is: $times should have all the times for all the $flight_details array, and then we populate, will create a row for each $times record, that way we don't need to implode, just put the direct value off the array. The problem is to achieve this...
If you want such format, first off, you need to separate the headers, 2014-05-10 ... etc since they are above. Then you need to take care of the format. The key is: every time slot assign it to the company. Consider this example:
<?php
$details = array( 1 => array( 1 => 1000, 2 => 'Company A', 3 => '2014-05-10', 4 => '10:00:00', 5 => '15:00:00', ), 2 => array( 1 => 2000, 2 => 'Company A', 3 => '2014-05-11', 4 => '10:00:00', 5 => '15:00:00', ), 3 => array( 1 => 3000, 2 => 'Company B', 3 => '2014-05-10', 4 => '10:00:00', 5 => '15:00:00', ), 4 => array( 1 => 4000, 2 => 'Company B', 3 => '2014-05-11', 4 => '16:00:00', 5 => '19:00:00', ), 5 => array( 1 => 5000, 2 => 'Company C', 3 => '2014-05-10', 4 => '10:00:00', 5 => '15:00:00', ), 6 => array( 1 => 5000, 2 => 'Company D', 3 => '2014-05-12', 4 => '10:00:00', 5 => '15:00:00', ),);
//properly sort the raw data
// get headers
$header_dates = array();
foreach($details as $value) {
$header_dates[] = $value[3];
}
$header_dates = array_unique($header_dates);
// reformat main data companies
foreach($details as $key => $value) {
$time = "$value[4] - $value[5]"; // use this as key
foreach($header_dates as $date) {
// simple initialization
if(!isset($final[$value[2]][$time][$date])) $final[$value[2]][$time][$date] = '';
}
$final[$value[2]][$time][$value[3]] = $value[2];
// then set them accordingly to their date and time
}
?>
<!-- format them inside the table -->
<table border="1" cellpadding="10">
<!-- print the headers -->
<thead><tr><td></td><?php foreach($header_dates as $value): ?><th><?php echo $value; ?></th><?php endforeach; ?></tr></thead>
<tbody>
<?php foreach($final as $key => $data): ?>
<?php foreach($data as $index => $element): ?>
<tr><td><?php echo $index; ?></td> <!-- loop they time -->
<?php foreach($element as $v):?>
<td><?php echo $v; ?></td> <!-- values (Company A, ...) -->
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
</tbody>
</table>
Sample Output
For the result to come like your expected one, you need to give:
<td>{explode("," $company_name)[0]}</td>
<td>{explode("," $company_name)[1]}</td>
In the headers, you need to give this way:
<td colspan="2">{$date}</td>
Note: The code I have provided is just a pseudo code. You need to write your own code. We can just guide you!