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>
Related
I have been stuck for days on this 'little' problem.
I have one array which contains specific data:
$data = array(
0 => array('id' => 8, 'month' => 1, 'cost' => 12500),
1 => array('id' => 8, 'month' => 2, 'cost' => 14200),
2 => array('id' => 9, 'month' => 1, 'cost' => 23000),
3 => array('id' => 9, 'month' => 2, 'cost' => 18000),
);
And this is the html table results i need to get:
Id Jan Feb Mar Apr May
8 12,500 14,200 10,200 10,300 11,000
9 23,000 18,000 21,320 10,642 14,636
How i can sort array to display this data in html table on view.ctp ?
I have tried using foreach loops but i really don't know how to put unique months and unique id like it is displayed above. I'm using CakePHP 2.x technology.
I appreciate every help. Thank you
Loop over your array and group into a new array based on the ID. Assign month=cost key-value pairs, using IDs as the grouping keys of your multidimensional array.
$by_id = [];
foreach($data as $x) {
$by_id[$x['id']][$x['month']] = $x['cost'];
// e.g. $by_id[8][2] = 14200;
}
This will turn your sample data into the following array:
array(2) {
[8] · array(2) {
[1] · int(12500)
[2] · int(14200)
}
[9] · array(2) {
[1] · int(23000)
[2] · int(18000)
}
}
That should be much easier to turn into a HTML table. For example like this:
$html = [];
$html[] = '<table>';
$html[] = '<tr><th>ID</th><th>Jan</th><th>Feb</th></tr>';
foreach($by_id as $id => $months) {
$html[] = '<tr>';
$html[] = "<td>{$id}</td>";
foreach($months as $month => $cost) {
$html[] = "<td>{$cost}</td>";
}
$html[] = '</tr>';
}
$html[] = '</table>';
echo implode("\n", $html);
I trust the code is clear enough without elaborate comments. Add months to the table header as necessary. Use e.g. number_format for $cost to format your monies. Be aware that the sample code above doesn't account for possible missing months for a given ID, it assumes symmetric data. Add checks and remedies if necessary. See demo at https://3v4l.org/7CFRf.
You should use a 2D array to display that kind of table.
Then the $data array might be like this:
$data = array(
0 => array('id' => 8, 'costData' => array(
0 => array('month' => 1, 'cost' => 12500),
1 => array('monnt' => 2, 'cost' => 14200)
),
1 => array('id' => 9, 'costData' => array(
0 => array('month' => 1, 'cost' => 23000),
1 => array('month' => 2, 'cost' => 18000)
)
);
To revert the $data array like this, the code below will be needed.
<?php
$newData = array();
for($i = 0; $i < count($data); $i++)
{
$newItem = array('id' => $data[$i]['id'], 'costData' => array(
'month' => $data[$i]['month'],
'cost' => $data[$i]['cost']
));
for($j = $i + 1; $j < count($data); $j++)
{
if($data[$j]['id'] == $data[$i]['id']) {
$newItem['costData'][] = array('month' => $data[$j]['month'], 'cost' => $data[$j]['cost']);
array_splice($data, $j, 1);
$j--;
}
}
$newData[] = $newItem;
}
Using new data Array, you can make your html page like this.
$html = '';
for($i = 0; $i < count($newData); $i++)
{
$html .= '<tr>';
$html .= '<td>'.($newData[$i]['id']).'</td>';
for($j = 0; $j < count($newData[$i]['costData']); $j++) {
$html .= '<td>'.($newData[$i]['costData'][$j]).'</td>';
// you can do some operations if there are missing months to leave blank td tags..
}
// fill the missing months to fill the td tags.
}
You could use a combination of the array_column() and array_sum() functions:
$data = array(
array('id' => 8, 'month' => 1, 'cost' => 12500),
array('id' => 8, 'month' => 2, 'cost' => 14200),
array('id' => 9, 'month' => 1, 'cost' => 23000),
array('id' => 9, 'month' => 2, 'cost' => 18000),
);
$result = array();
foreach ($data as $row) {
$result[$row['id']][$row['month']] = $row['cost'];
}
// Sum the costs for each month
$months = array_column($data, 'month');
$result = array_map(function($v) use ($months) {
return array_sum(array_intersect_key($v, array_flip($months)));
}, $result);
print_r($result);
This will output:
Array
(
[8] => Array
(
[1] => 12500
[2] => 14200
)
[9] => Array
(
[1] => 23000
[2] => 18000
)
)
I have a very simple multidimensional array and some PHP code. The code should print the p_id values, but it does not do it. Do I really have to add one foreach more or is there other ways?
And here is the array:
Array (
[2764] => Array (
[status] => 0
[0] => Array (
[p_id] => 2895
)
[1] => Array (
[p_id] => 1468
)
)
[5974] => Array (
[status] => 0
[0] => Array (
[p_id] => 145
)
[1] => Array (
[p_id] => 756
)
)
)
Here is my PHP code:
foreach($arr as $innerArray)
foreach($innerArray as $key => $value)
echo $key . "=>" . $value . "<br>";
It prints:
status=>0
0=>Array
1=>Array
status=>0
0=>Array
1=>Array
foreach($arr as $a => $a_value)
{
echo $a . '<br>';
foreach($a_value as $av_arr => $av)
{
if(!is_array($av))
{
echo $av_arr . '=>' . $av . '<br>';
}
else
{
foreach($av as $inner_av => $inner_av_val)
{
echo $inner_av . '=>' . $inner_av_val . '<br>';
}
}
}
}
This simple call to array_walk_recursive() produces the output requested in the question:
array_walk_recursive(
$arr,
function ($value, $key) {
echo $key . "=>" . $value . "<br>";
}
);
But it doesn't make much sense as the output mixes the values of status with the values of p_id.
I would go for a more structured display using the original code with a little more meaning for the names of the variables:
foreach ($arr as $catId => $catInfo) {
// Category ID and details; use other names if I'm wrong
printf("Category: %d (status: %s)\n", $catId, $catInfo['status'] ? 'active' : 'inactive');
foreach ($catInfo as $key => $value) {
if ($key == 'status') {
// Ignore the status; it was already displayed
continue;
}
foreach ($value as $prodInfo) {
printf(" Product ID: %d\n", $prodInfo['p_id']);
}
}
}
The structure of the input array tells me you should first fix the code that generates it. It should group all the products (the values that are now indexed by numeric keys) into a single array. It should look like this:
$input = array(
'2764' => array(
'status' => 0,
'products' => array(
2895 => array(
'p_id' => 2895,
'name' => 'product #1',
// more product details here, if needd
),
1468 => array(
'p_id' => 1468,
'name' => 'product #2',
),
// more products here
),
// more categories here
),
Then the code that prints it will look like this:
foreach ($arr as $catId => $catInfo) {
// Category ID and details; use other names if I'm wrong
printf("Category: %d (status: %s)\n", $catId, $catInfo['status'] ? 'active' : 'inactive');
foreach ($catInfo['products'] as $prodInfo) {
printf(" %s (ID: %d)\n", $prodInfo['name'], $prodInfo['p_id']);
// etc.
}
}
Use a recursive function:
function printIds($arr) {
foreach ($arr as $key => $val) {
if (is_array($val) && array_key_exists("p_id", $val)) {
echo $val["p_id"]."\n";
} elseif(is_array($val)) {
printIds($val);
}
}
}
Working example:
$arr = [
2764 => [
'status' => 0,
['p_id' => 100],
],
4544 => [
'status' => 0,
['p_id' => 100],
],
['p_id' => 100],
];
function printIds($arr) {
foreach ($arr as $key => $val) {
if (is_array($val) && array_key_exists("p_id", $val)) {
echo $val["p_id"]"\n";
} elseif(is_array($val)) {
printIds($val);
}
}
}
printIds($arr);
The function loops all entries of a given array and echo's them out, if they contain an array with a key named "p_id". If it does find a nested array, then it does loop also all child arrays.
I have an array like that contain key with same name but with number at the end
array example:
Array
(
[field_name0] => name
[field_name1] => sku_package_height
[field_name2] => sku_package_width
[custom_field] => 13
[attribute] => 'test'
[field_name3] => sku_package_length
[field_name4] => sku_package_weight
)
from the example above i want to count how many record that has array key that contain field_name, so the result I want will be 5
you can do this :
$count = 0;
foreach($array as $key => $value){
if(strpos($key,"field_name") > -1){
$count++;
}
}
$count will have number of keys.
You can do it like below:-
<?php
$original_array = Array
(
'field_name0' => 'name',
'field_name1' => 'sku_package_height',
'field_name2' => 'sku_package_width',
'custom_field' => 13,
'attribute' => 'test',
'field_name3' => 'sku_package_length',
'field_name4' => 'sku_package_weight'
);
$search = "field_name";
$counter = 0;
foreach($original_array as $key=> $value){
if(strstr($key,$search)){
$counter = $counter+1;
}
}
echo $counter;
Output:-https://eval.in/704506
Or
<?php
$original_array = Array
(
'field_name0' => 'name',
'field_name1' => 'sku_package_height',
'field_name2' => 'sku_package_width',
'custom_field' => 13,
'attribute' => 'test',
'field_name3' => 'sku_package_length',
'field_name4' => 'sku_package_weight',
);
$search = "field_name";
$counter = 0;
foreach($original_array as $key=> $value){
if(is_numeric(strpos($key,$search))){
$counter = $counter+1;
}
}
echo $counter;
Output:-https://eval.in/704518
Check the isnumeric of the string position "field_name" in key
$i= 0;
foreach($arrayfields as $keys => $values){
if (is_numeric(strpos($keys,"field_name"))){
$i++;
}
}
echo $i;
<?php
$array=array("field_name0"=>"name","field_name1"=>"sku_package_height ","field_name2"=>"sku_package_width","custom_field"=>"13","attribute"=>"test","field_name3"=>"sku_package_length", "field_name4"=>"sku_package_weight");
echo $arraykey= count(preg_grep("/^field_name(\d)+$/",array_keys($array)));
?>
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>';
}
So, I want to print the following three dimensional array in an HTML table.
array ( 'BTC_YACC' => array ( 0 => array ( 'orderNumber' => '3585379', 'type' => 'sell', 'rate' => '0.0001', 'amount' => '128', 'total' => '0.0128', 'date' => '2014-05-18 08:54:37', ), ), )
This is what I came up with: (OrderNumber = OrderID).
$tableopenorders = "<table><th>OrderID</th><th>Type</th><th>Rate</th><th>Amount</th><th>Total in BTC</th><th>Date placed</th><tr>";
for($element = 0; $element < count($decodedopenorders); $element++) {
$tableopenorders .= "<tr>";
for($row = 0; $row < 1; $row++) {
for ($col = 0; $col < 6; $col++) {
$tableopenorders .= "<td>".$decodedopenorders[$element][$row][$col]."</td>";
}
}
$tableopenorders .= "</tr>";
}
$tableopenorders .= "</table>";
There's a maximum of "count($decodedopenorders)" $elements, max. 1 $row and 6 rows in the $decodedopenorders array. The iterator starts a 0, so I used <.
Why does this not work?
When you loop through your arrays you have changed the key to be something other than the typical 0, 1, 2, 3. When you change the key the $decodedopenorders[0] no longer works and instead you would have to call $decodedopenorders['BTC_YACC']; So here is the code I got to work:
$decodedopenorders = array (
'BTC_YACC' => array (
0 => array (
'orderNumber' => '3585379',
'type' => 'sell',
'rate' => '0.0001',
'amount' => '128',
'total' => '0.0128',
'date' => '2014-05-18 08:54:37')
)
);
$tableopenorders = "<table><th>OrderID</th><th>Type</th><th>Rate</th><th>Amount</th><th>Total in BTC</th><th>Date placed</th><tr>";
foreach ($decodedopenorders as $element => $value) {
$tableopenorders .= "<tr>";
foreach ($decodedopenorders[$element] as $row => $value){
foreach ($decodedopenorders[$element][$row] as $order) {
$tableopenorders .= "<td>". $order ."</td>";
}
}
$tableopenorders .= "</tr>";
}
$tableopenorders .= "</table>";
echo $tableopenorders;