New to PHP and after spending hours researching on here, nothing seems to be exactly what I need. I have a multi dimensional array that I'm looking to pull data and COUNT from. FOR Instance:
array (
'loyola' => NULL,
'gold_coast' => NULL,
'lincolnpark' =>
array (
0 => 'Building 1',
1 => 'Building 2',
2 => 'Building 3',
3 => 'Building 4'
),
'lakeview' =>
array (
0 => 'Building 1',
1 => 'Building 2',
2 => 'Building 3'
),
)
I'm looking to essentially create a table that lists all the buildings and in the next column the number of times that building appears.
This what I've gotten thus far, but it only displays all buildings.
$buildings = unserialize($row['buildings']);
$lincolnpark = $buildings['lincolnpark'];
$loyola= $buildings['loyola'];
$gold_coast = $buildings['gold_coast'];
$lakeview = $buildings['lakeview'];
foreach ($lakeview as $value)
{
echo $value;
}
}
Try the code below. It will navigate recursively into the array and will print the qtd each build appear.
<?php
$arr = array (
'loyola' => NULL,
'gold_coast' => NULL,
'lincolnpark' =>
array (
0 => 'Building 1',
1 => 'Building 2',
2 => 'Building 3',
3 => 'Building 4'
),
'lakeview' =>
array (
0 => 'Building 1',
1 => 'Building 2',
2 => 'Building 3'
),
);
$ret = array();
countBuildings($arr);
foreach($ret as $key=>$value){
echo "Building: $key ==> qtd : $value <br>";
}
function countBuildings($arr = array()){
global $ret;
foreach($arr as $value){
if(is_array($value)){
countBuildings($value);
}else{
if($value != NULL){
if(isset($ret[$value])){
$ret[$value] += 1;
}else{
$ret[$value] = 1;
}
}
}
}
}
Do it in two passes: one for counting building occurrences in a separate array, and another for output.
Related
I have this array :
(
[id] => block_5df755210d30a
[name] => acf/floorplans
[data] => Array
(
[floorplans_0_valid_for_export] => 0
[floorplans_0_title] => title 1
[floorplans_0_house_area] => 40m²
[floorplans_0_bedrooms] => 1
[floorplans_1_valid_for_export] => 1
[floorplans_1_title] => title xx
[floorplans_1_house_area] => 90m²
[floorplans_1_bedrooms] => 2
[floorplans_2_valid_for_export] => 1
[floorplans_2_title] => title 2
[floorplans_2_house_area] => 50m²
[floorplans_2_bedrooms] => 1
[floorplans] => 3
)
)
As we can see in the data, we have fields (floorplans_X_valid_for_export).
What I want to do is to get the data only when this field equal to 1.
So from the given example, I want to keep only these fields:
[floorplans_1_valid_for_export] => 1
[floorplans_1_title] => title xx
[floorplans_1_house_area] => 90m²
[floorplans_1_bedrooms] => 2
[floorplans_2_valid_for_export] => 1
[floorplans_2_title] => title 2
[floorplans_2_house_area] => 50m²
[floorplans_2_bedrooms] => 1
This is an odd schema, but it can be done by iterating through the array and searching for keys where "valid_for_export" equals 1, and then using another array of field "stubs" to get the associated items by a unique identifier of X in floorplans_X_valid_for_export
$array = [
'floorplans_0_valid_for_export' => 0,
'floorplans_0_title' => 'title 1',
'floorplans_0_house_area' => '40m²',
'floorplans_0_bedrooms' => 1,
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
'floorplans' => 3
];
$stubs = [
'floorplans_%s_valid_for_export',
'floorplans_%s_title',
'floorplans_%s_house_area',
'floorplans_%s_bedrooms'
];
$newArr = [];
foreach ($array as $key => $value) {
if (strpos($key, 'valid_for_export') && $array[$key] == 1) {
$intVal = filter_var($key, FILTER_SANITIZE_NUMBER_INT);
foreach ($stubs as $stub) {
$search = sprintf($stub, $intVal);
if (isset($array[$search])) {
$newArr[$search] = $array[$search];
} else {
// key can't be found, generate one with null
$newArr[$search] = null;
}
}
}
}
echo '<pre>';
print_r($newArr);
Working: http://sandbox.onlinephpfunctions.com/code/23a225e3cefa2dc9cc97f53f1cbae0ea291672c0
Use a parent loop to check that the number-specific valid_for_export value is non-empty -- since it is either 0 or non-zero.
If so, then just push all of the associated elements into the result array.
Some reasons that this answer is superior to the #Alex's answer are:
Alex's parent loop makes 13 iterations (and the same number of strpos() calls); mine makes just 3 (and only 3 calls of empty()).
$array[$key] is more simply written as $value.
Sanitizing the $key to extract the index/counter is more overhead than necessary as demonstrated in my answer.
Code (Demo)
$array = [
'floorplans_0_valid_for_export' => 0,
'floorplans_0_title' => 'title 1',
'floorplans_0_house_area' => '40m²',
'floorplans_0_bedrooms' => 1,
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
'floorplans' => 3
];
$labels = ['valid_for_export', 'title', 'house_area', 'bedrooms'];
$result = [];
for ($i = 0; $i < $array['floorplans']; ++$i) {
if (!empty($array['floorplans_' . $i . '_valid_for_export'])) {
foreach ($labels as $label) {
$key = sprintf('floorplans_%s_%s', $i, $label);
$result[$key] = $array[$key];
}
}
}
var_export($result);
Output:
array (
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
)
With that constructed data it might be hard (not impossble tho), hovewer i would suggest to change it to multidimensional arrays so you have something like:
[floorplans][0][valid_for_export] => 0
[floorplans][0][title] => title 1
[floorplans][0][house_area] => 40m²
[floorplans][0][bedrooms] => 1
[floorplans][1][valid_for_export] => 1
[floorplans][1][title] => title xx
[floorplans][1][house_area] => 90m²
Rought sollution
It is not the best approach, but it should work if you dont need anything fancy, and know that structure of data wont change in future
$keys = [];
$for($i=0;$i<$array['floorplans'];++$i) {
if(isset($array['floorplans_'.$i.'_valid_for_export']) && $array['floorplans_'.$i.'_valid_for_export']===1) {
$keys[] = $i;
}
}
print_r($keys);
This question already has answers here:
multidimensional array array_sum
(10 answers)
Closed 5 years ago.
I need help regarding foreach and arrays in PHP
Say I have the following array:
$orders = array (
0 =>
array (
'company' => 'Company 1',
'total' => '5',
),
1 =>
array (
'company' => 'Company 2',
'total' => '10',
),
2 =>
array (
'company' => 'Company 1',
'total' => '15',
),
3 =>
array (
'company' => 'Company 1',
'total' => '5',
),
4 =>
array (
'company' => 'Company 3',
'total' => '12',
)
);
Order 1 is 5 for Company 1
Order 2 is 10 for Company 2
Order 3 is 15 for Company 1
Order 4 is 5 for Company 2
Order 5 is 12 for Company 3
I want the output to show the company name and the accumulative total of each company's orders
For example:
Company 1 20
Company 2 15
Company 3 12
Just create another array that will track the orders.
$companies = array();
foreach ($orders as $order) {
if (array_key_exists($order["company"], $companies)) {
$companies[$order["company"]] += $order["total"];
} else {
$companies[$order["company"]] = $order["total"];
}
}
First, we check if the company is already in the companies array, if it is then we add the total to that company's current total.
Otherwise, we just create a new key and store the total.
Additionally, you can write (int)$order["total"] to typecast into integer.
This might be useful to ensure that you have the correct data.
array_reduce() solution:
$groups = array_reduce($orders, function($r, $a) {
$k = $a['company'];
(isset($r[$k]))? $r[$k] += $a['total'] : $r[$k] = $a['total'];
return $r;
}, []);
foreach ($groups as $k => $v) {
printf("%-20s%d\n", $k, $v);
}
The output:
Company 1 25
Company 2 10
Company 3 12
One way to do this with a foreach loop where you increment some variable :
// Your array
$array = array(...);
// Init of the sum of each total for each company
$c1 = 0;
$c2 = 0;
$c3 = 0;
// You loop through your array and test the output
foreach ($array as $order => $value_array) {
switch($value_array['company']) {
case 'Company 1' : $c1 += intval($value_array['total']); break;
case 'Company 2' : $c2 += intval($value_array['total']); break;
case 'Company 3' : $c3 += intval($value_array['total']); break;
}
}
//$c1 will be the sum for company 1;
//$c2 for the company 2;
//$c3 for the company 3.
Is it what you are looking for?
Just another way: array_walk
$result = array();
array_walk($orders, function ($element) use (&$result) {
$company = $element['company'];
if (!isset($result[$company]))
$result[$company] = 0;
$result[$company] += $element['total'];
});
For this input:
$orders = array(
0 =>
array(
'company' => 'Company 1',
'total' => '5',
),
1 =>
array(
'company' => 'Company 2',
'total' => '10',
),
2 =>
array(
'company' => 'Company 1',
'total' => '15',
),
3 =>
array(
'company' => 'Company 1',
'total' => '5',
),
4 =>
array(
'company' => 'Company 3',
'total' => '12',
)
);
The output will be:
array(3) {
["Company 1"]=>
int(25)
["Company 2"]=>
int(10)
["Company 3"]=>
int(12)
}
I need to get all "top level" keys from multidimensional array by searching the "bottom level" values. Here is an example of the array:
$list = array (
'person1' => array(
'personal_id' => '1',
'short_information' => 'string',
'books_on_hand' => array(
'Book 1',
'Book 2',
'Book 3',
)
),
'person2' => array(
'personal_id' => '2',
'short_information' => 'string',
'books_on_hand' => array(
'Book 4',
'Book 2',
'Book 5',
)
),
'person3' => array(
'personal_id' => '3',
'short_information' => 'string',
'books_on_hand' => array(
'Book 4',
'Book 2',
'Book 1',
'Book 3',
)
),
//etc...
);
I want to know all persons who have "Book 2" on hand. I can get that information by loop like this:
foreach ($list as $person => $info){
$check = array_search( 'Book 2', array_column($info, 'books_on_hand') );
if ( $check !== false ){
$results .= 'Name: '.$person;
$results .= 'ID: '.$info['personal_id'];
//get other infos other stuff, if necessary
}
}
The problem is, that foreach in this case is very heavy on memory and only grows more when array has a thousand+ entries. It needs to run through all of the persons, even if only 3 persons at the very top of the array have "Book 2".
I have been trying to optimize it by getting persons with "Book 2" using built-in functions like array_search, array_keys, array_column and only then run foreach for persons found, but I had no luck with getting "top level" keys.
Is it possible to optimize or use built-in function to search multidimensional array?
One way would be to filter it first. Now your result is structured like $list but it only contains elements with the needed book:
$find = 'Book 2';
$result = array_filter($list, function($v) use($find) {
return in_array($find, $v['books_on_hand']);
});
If all you're interested in is the person key and personal_id then this:
$find = 'Book 2';
$result = array_map(function($v) use($find) {
if(in_array($find, $v['books_on_hand'])) {
return $v['personal_id'];
}
}, $list);
Will return something like this for persons with the needed book:
Array
(
[person1] => 1
[person2] => 2
[person3] => 3
)
I am trying to build multidimensional to get json but its getting little complex. Sure there is easier way to do this. Here is my code.
$rows = array();
$idx = 0;
$sql = "SELECT products, GROUP_CONCAT(title,',' ,price SEPARATOR ', ' ) prods FROM mylist GROUP BY products";
$query = mysqli_query($con, $sql);
while($row = mysqli_fetch_assoc($query)){
$rows[$idx]['products'] = $row['products'];
$title = explode(',',$row['prods']);
$rows[$idx]['prods'] = $title;
$idx++;
};
echo '<pre>' . var_export($rows, true) . '</pre>';
echo json_encode($rows);
It give me this result
array (
0 =>
array (
'prods' =>
array (
0 => 'title 4',
1 => '4',
2 => ' title 1',
3 => '1',
),
),
1 =>
array (
'prods' =>
array (
0 => 'title 2',
1 => '21',
),
),
2 =>
array (
'prods' =>
array (
0 => 'title 3',
1 => '3',
),
),
)
[{"prods":["title 4","4"," title 1","1"]},{"prods":["title 2","21"]},{"prods":["title 3","3"]}]
But I want like this
array (
0 =>
array (
'prods' =>
array (
array(title => 'title 4', price => '4'),
array(title => ' title 1', price => '1'),
),
),
1 =>
array (
'prods' =>
array (
array(title => 'title 2', price => '21'),
),
),
2 =>
array (
'prods' =>
array (
array(title => 'title 3', price => '3'),
),
),
)
[
{
"prods": [
{
"title": "title 4",
"price": "4"
},
{
"title": "title1",
"price": "1"
}
]
},
{
"prods": [
{
"title": "title2",
"price": "21"
}
]
},
{
"prods": [
{
"title": "title3",
"price": "3"
}
]
}
]
So, not sure how to mix the exploded data on array to get the right json encoded.
You can do a foreach on the $title array and if the key is even then build the output array with the desired keys. In the below I edited to substituted your db query for json so that the full example can be included without the sql query.
$rows = array();
$idx = 0;
$data = json_decode('[{"products":"the product", "prods":"title 4,4,title 1,1"},{"products":"the product", "prods":"title 2,21"},{"products":"the product", "prods":"title 3,3"}]', true);
foreach ($data as $row)
{
$rows[$idx]['products'] = $row['products'];
$title = explode(',',$row['prods']);
foreach ($title as $k => $v) {
// check if even
if ($k % 2 == 0) $rows[$idx]['prods'][] = array('title' => $v, 'price' => $title[$k+1]);
}
$idx++;
};
echo '<pre>' . var_export($rows, true) . '</pre>';
echo json_encode($rows);
Will output the following
array (
0 =>
array (
'products' => 'the product',
'prods' =>
array (
0 => array ('title' => 'title 4','price' => '4'),
1 => array ('title' => 'title 1','price' => '1'),
),
),
1 =>
array (
'products' => 'the product',
'prods' =>
array (
0 => array ('title' => 'title 2','price' => '21'),
),
),
2 =>
array (
'products' => 'the product',
'prods' =>
array (
0 => array ('title' => 'title 3','price' => '3'),
),
),
)
Based on Tristan earlier suggestion, I was able to get the expected result with below code, not sure if that's the best way.
$rows = array();
$idx = 0;
$sql = "SELECT products, GROUP_CONCAT(title,',',price SEPARATOR ';') prods FROM mylist GROUP BY products";
$query = mysqli_query($con, $sql);
while($row = mysqli_fetch_assoc($query)){
$prods = explode(';',$row['prods']);
foreach ($prods as $key => $value) {
$expValue = explode(',',$value);
$rows[$idx]['prods'][] = array('title' => $expValue[0], 'price' => $expValue[1]);
};
$idx++;
};
echo '<pre>' . var_export($rows, true) . '</pre>';
echo json_encode($rows);
I'm trying to pass some of the values from theOptions array and drop them into a new array called $theDefaults.
$theOptions = array(
'item1' => array('title'=>'Title 1','attribute'=>'Attribute 1','thing'=>'Thing 1'),
'item2' => array('title'=>'Title 2','attribute'=>'Attribute 2','thing'=>'Thing 2'),
'item3' => array('title'=>'Title 3','attribute'=>'Attribute 3','thing'=>'Thing 3')
);
So, $theDefaults array should look like this:
$theDefaults = array(
'Title 1' => 'Attribute 1',
'Title 2' => 'Attribute 2',
'Title 3' => 'Attribute 3'
);
However, I cannot figure out how to do this.
Have tried this but it is clearly not quite working.
$theDefaults = array();
foreach($theOptions as $k=>$v) {
array_push($theDefaults, $v['title'], $v['attribute']);
}
but when I run this...
foreach($theDefaults as $k=>$v) {
echo $k .' :'.$v;
}
It returns this.
0 :Title 11 :Attribute 12 :Title 23 :Attribute 24 :Title 35 :Attribute 3
Looks to be soooo close, but why are the numbers in the array?
It's even simpler than that:
$theDefaults = array();
foreach($theOptions as $v) {
$theDefaults[$v['title']] = $v['attribute'];
}