How to foreach multidimensional array with key value - php

I have a multidimensional array with key value. I want to loop the data in that array but I don't know how.
This is my array:
$myArray= Array
(
'134' => Array
(
'1138' => Array
(
'id' => 1138,
'qty' => 1,
'price' => 4900000,
'name' => 'Pioneer AVH X5850BT Head Unit Double Din 7Inch',
'options' => Array
(
'image' => '865e6ad631fa45d408acfc6f8a8ff008.jpg',
'created_by' => 134
),
'rowid' => 'f9e62f7ce9665a25ff40848744dd83f4',
'subtotal' => 4900000
),
'1003' => Array
(
'id' => 1003,
'qty' => 1,
'price' => 2250000,
'name' => 'Steelmate SW813 Subwoofer Aktif 10 Inch',
'options' => Array
(
'image' => '962df806d5adc7bd0d22666fe996f139.jpg',
'created_by' => 134
),
'rowid' => '7aa455ef597b2906e3895783bd7a5c70',
'subtotal' => 2250000
)
),
'157' => Array
(
'2527' => Array
(
'id' => 2527,
'qty' => 1,
'price' => 2475000,
'name' => 'Rockford Fosgate P165SE Speaker Split 2way Komponen',
'options' => Array
(
'image' => '81027273a2ad59a96aec85ec66ce2704.jpg',
'created_by' => 157
),
'rowid' => 'ed9301accd0d84bd0417609aa80cebc7',
'subtotal' => 2475000
)
)
);
How do I loop / foreach that array?
I guess there is a foreach inside a foreach, but I don't know how to do that.

You can use a recursive function here, so you don't need to worry how deep your array will be.
Something like this:
function read($arr) {
foreach ($arr as $key => $value) {
if (is_array($value)) {
read($a);
}
else {
// You cann access key and value here (for each array)
}
}
}
read($myArray);

Just use another foreach inside your foreach
foreach ($myArray as $key => $value) {
foreach ($value as $subkey => $subvalue) {
if (is_array($subvalue)) {
foreach ($subvalue as $subsubkey => $subsubvalue) {
// .... and so on
}
}
}
}

/* loop across $myArray (listing elements 134 and 157) */
foreach ($myArray as $groupId => $group) {
echo "walking through group $groupId" . PHP_EOL;
/* loop across "groups" 134 and 157 (listing elements 1138, 1003, etc.) */
foreach ($group as $itemId => $item) {
echo "walking through item $itemId" . PHP_EOL;
/* loop each "item" record in key/value pairs */
foreach ($item as $key => $value) {
echo "$key: ";
/* deal with options sub-array */
if (is_array($value)) {
foreach ($value as $option => $optionValue) {
echo " $option: $optionValue" . PHP_EOL;
}
} else {
echo $value . PHP_EOL;
}
}
}
}

Related

Filter array with array_walk_recursive but deny specific values

I am trying to filter an array
$array = [
[
'id' => 1,
'some_key' => 'some_value',
'attribute' => [
'id' => 45,
'cat_id' => 1
],
'sub' => [
'id' => 17,
'some_key' => 'some_value',
'attribute' => [
'id' => 47,
'cat_id' => 17
],
],
],
[
'id' => 2,
'some_key' => 'some_value',
'sub' => [
'id' => 19,
'some_key' => 'some_value',
],
]
];
$childArray = [];
array_walk_recursive($array, static function($value, $key) use(&$childArray){
if($key === 'id') {
$childArray[] = $value;
}
});
This returns me an array of all array-fields having id as key.
[1,45,17,47,2,19]
But there is a small problem, some of the array have an key called attribute containing an idkey field that I dont want to have.
[1,17,2,19] //this is what I want
Is there a way to say "don't take the id inside attribute" ?
My current solution, I added a filter before my filter :D
/**
* #param array $array
* #param string $unwanted_key
*/
private function recursive_unset(&$array, $unwanted_key)
{
unset($array[$unwanted_key]);
foreach ($array as &$value) {
if (is_array($value)) {
$this->recursive_unset($value, $unwanted_key);
}
}
}
but this seems like this is not the best practice ^^
You can traverse recursively manually instead of array_walk_recursive and avoid all under attribute key.
<?php
$childArray = [];
function collectIDs($arr,&$childArray){
foreach($arr as $key => $value){
if($key === 'attribute') continue;
if(is_array($value)) collectIDs($value,$childArray);
else if($key === 'id') $childArray[] = $value;
}
}
collectIDs($array,$childArray);
print_r($childArray);
Demo: https://3v4l.org/V6uFf
Find a function that will flatten your array. The result should look like this (I have a class for this):
array (
0 =>
array (
'id' => 1,
'some_key' => "some_value",
'attribute.id' => 45,
'attribute.cat_id' => 1,
'sub.id' => 17,
'sub.some_key' => "some_value",
'sub.attribute.id' => 47,
'sub.attribute.cat_id' => 17,
),
1 =>
array (
'id' => 2,
'some_key' => "some_value",
'sub.id' => 19,
'sub.some_key' => "some_value",
),
)
So you have all keys available and can work with a modified array_walk.
$childArray = [];
array_walk_recursive($data, static function($value, $key) use(&$childArray){
$keys = array_reverse(explode(".",$key));
if($keys[0] === 'id' AND (!isset($keys[1]) OR $keys[1] != 'attribute')) {
$childArray[] = $value;
}
});
The RecursiveArrayIterator class is also very suitable when array values ​​are to be collected depending on keys and values ​​on different levels.
$result = [];
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach($it as $key => $value) {
$parentLevel = $it->getDepth()-1;
$parentKey = $it->getSubIterator($parentLevel)->key();
if($key === 'id' AND $parentKey !== 'attribute'){
$result[] = $value;
}
}
var_export($result);
//array ( 0 => 1, 1 => 17, 2 => 2, 3 => 19, )
To return the qualifying ids instead of creating a reference variable, merge recursive calls of the function as you iterate.
Code: (Demo)
function getIds($array) {
$ids = [];
foreach ($array as $key => $value) {
if ($key === 'id') {
$ids[] = $value;
} elseif ($key !== 'attribute' && is_array($value)) {
$ids = array_merge($ids, getIds($value));
}
}
return $ids;
}
var_export(getIds($array));
Output:
array (
0 => 1,
1 => 17,
2 => 2,
3 => 19,
)

PHP foreach with multidimensional array not printing all values

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.

php array how get in array value for using foreach

I have multiple array, I want particular value get using foreach below my code
Notice: Undefined index: transId in on line 52
$test = array(
'messages' => Array
(
'resultCode' => 'Ok',
'message' => Array
(
'code' => 'I00001',
'text' => 'Successful',
),
),
'transactionResponse' => Array
(
'responseCode' => '1',
'authCode' => 'Z7K31J',
'avsResultCode' => 'Y',
'cvvResultCode' => 'P',
'cavvResultCode' => '2',
'transId' => '40004672975',
'refTransID' => Array
(
),
'transHash' => '163382584395AB06470CF365AD6F7381',
'testRequest' => '0',
'accountNumber' => 'XXXX4242',
'accountType' => 'Visa',
'messages' => Array
(
'message' => Array
(
'code' => '1',
'description' => 'This transaction has been approved',
),
),
'transHashSha2' => Array
(
),
),
);
above my array, execute $test in foreach
I want display value of transid, response, transhash
foreach ($test as $key => $value) {
$response = $value['resultCode'];
$transId = $value['transId'];
$authCode = $value['authCode'];
$transHash = $value['transHash'];
}
use array_walk_recursive() where you don't have to go in each level of the array to echo your values like below:
<?php
array_walk_recursive($test, function ($item, $key){
if($key == 'transId' || $key == 'transHash' || $key == 'resultCode'){
echo $key." => ".$item."<br>";
}
});
You dont need foreach:
$response = $test['messages']['resultCode'];
$transId = $test['transactionResponse']['transId'];
$authCode = $test['transactionResponse']['authCode'];
$transHash = $test['transactionResponse']['transHash'];
you can use this
foreach ($test as $key => $value)
{
if(!empty($value['message']))
{
$response = $value['messages']['resultCode'];
}
elseif(!empty($value['transactionResponse']))
{
$transId = $value['transactionResponse']['transId'];
$authCode = $value['transactionResponse']['authCode'];
$transHash = $value['transactionResponse']['transHash'];
}
}
if you want proper then you have to take it to array and key as your transid

Add value to existing array key in foreach loop

I have the following bibliography data in an array (note that fields are in random order - there are others fields as well):
Array
(
[0] => Array
(
['Pub_Name'] => Nature
['Volume'] => 6
['Pages'] => 215-217
)
[1] => Array
(
['Volume'] => 15
['Pages'] => 358-360
['Pub_Name'] => Science
)
[2] => Array
(
['Pub_Name'] => PNAS
['Pages'] => 17-19
['Volume'] => 22
)
)
I want to "merge" those three fields into one, for example ['Pub_Name']=Nature, 6: 215-217. I tried the following whitout success (I guess $Record['Pub_Name'] is the incorrect sintax):
foreach ($MyArray as $Record) {
foreach ($Record as $key => $values) {
if ($key=="Volume") {$Volumen=", ".$values;} else {$Volumen="";}
if ($key=="Pages") {$Paginas=": ".$values;} else {$Paginas="";}
}
//This is the line for which I want to know the sintax!!
$Record['Pub_Name'].=$Volumen.$Paginas;
}
No need for two loops:
foreach ($MyArray as $Record) {
$result[]['Pub_Name'] = "{$Record['Pub_Name']}, {$Record['Pages']}: {$Record['Volume']}";
}
Then you have the new Pub_Name entries in $result.
If you want to modify the original then reference & $Record:
foreach ($MyArray as &$Record) {
$Record['Pub_Name'] = "{$Record['Pub_Name']}, {$Record['Pages']}: {$Record['Volume']}";
}
Or use the key and modify the original array:
foreach ($MyArray as $key => $Record) {
$MyArray[$key]['Pub_Name'] = "{$Record['Pub_Name']}, {$Record['Pages']}: {$Record['Volume']}";
}
PHP code demo
<?php
$array=Array
(
0 => Array
(
'Pub_Name' => "Nature",
'Volume' => 6,
'Pages' => "215-217"
),
1 => Array
(
'Volume' => 15,
'Pages' => "358-360",
'Pub_Name' => "Science"
),
2 => Array
(
'Pub_Name' => 'PNAS',
'Pages' => "17-19",
'Volume' => 22
)
);
$result=array();
foreach ($array as $data)
{
$result[]=array('Pub_Name'=> $data['Pub_Name'].", ".$data["Volume"].": ".$data["Pages"]);
}
print_r($result);
Output:
Array
(
[0] => Array
(
[Pub_Name] => Nature, 6: 215-217
)
[1] => Array
(
[Pub_Name] => Science, 15: 358-360
)
[2] => Array
(
[Pub_Name] => PNAS, 22: 17-19
)
)
I guess this is what you are looking for:
<?php
$input = [
[
'Pub_Name' => 'Nature',
'Volume' => '6',
'Pages' => '215-217'
],
[
'Volume' => '15',
'Pages' => '358-30',
'Pub_Name' => 'Science',
],
[
'Pub_Name' => 'PNAS',
'Pages' => '17-19',
'Volume' => '22'
]
];
$output = [];
array_walk($input, function ($entry) use (&$output) {
$output[] = sprintf(
'%s, %s: %s',
$entry['Pub_Name'],
$entry['Volume'],
$entry['Pages']
);
});
print_r($output);
The output of above code obviously is:
Array
(
[0] => Nature, 6: 215-217
[1] => Science, 15: 358-30
[2] => PNAS, 22: 17-19
)
Use array_map
$in = [
0 => [
'Pub_Name' => 'Nature',
'Volume' => 6,
'Pages' => '215-217'
],
1 => [
'Volume' => 15,
'Pages' => '358-360',
'Pub_Name' => 'Science',
],
2 => [
'Pub_Name' => 'PNAS',
'Pages' => '17-19',
'Volume' => 22
]
];
array_map(function ($item) {
return $item['Pub_Name'] . ', ' . $item['Volume'] . ': ' . $item['Pages'];
}, $in);
There are a few different ways to do this - but one of the more readable ways:
// create a copy of the original - so we aren't looping thru the same array we're updating
$updatedArray = $MyArray;
foreach ($MyArray as $index => $record) {
$updatedArray[$index]['Pub_Name'] =
$record['Pub_Name'].
($record['Volume'] ? ', '.$record['Volume'] : '').
($record['Pages'] ? ': '.$record['Pages']:'');
}
Clear way in a single loop. Use sprintf() for easy formatting:
<?php
$src =[ ['Pub_Name' => 'Nature', 'Volume' => '6', 'Pages' => '215-217'],
['Volume' => '15', 'Pages' => '358-30', 'Pub_Name' => 'Science'],
['Pub_Name' => 'PNAS', 'Pages' => '17-19', 'Volume' => '22']
];
foreach ($src as $element) {
$dest[] = sprintf("%s, %d: %s",
$element['Pub_Name'],
$element['Volume'],
$element['Pages']);
}
var_dump($dest);
?>
And you get:
array(3) {
[0]=> string(18) "Nature, 6: 215-217"
[1]=> string(19) "Science, 15: 358-30"
[2]=> string(15) "PNAS, 22: 17-19"
}
Test it here.
This should help:
$combined = [];
foreach($myArray as $pub) {
$combined.push($pub['Pub_Name'] . ', ' . $pub['Volume'] . ': ' . $pub['Pages']);
}

unable to delete array key from multidimensional array in cakephp

I want to delete array index which contain rating 0 here is my array
array(
(int) 0 => array(
'Gig' => array(
'id' => '1',
'rating' => (int) 5
)
),
(int) 1 => array(
'Gig' => array(
'id' => '3',
'rating' => (int) 9
)
),
(int) 2 => array(
'Gig' => array(
'id' => '4',
'rating' => '0'
)
)
)
and what I did
for($i = 0; $i<count($agetGigsItem); $i++)
{
if($agetGigsItem[$i]['Gig']['rating']==0)
{
unset($agetGigsItem[$i]);
}
$this->set('agetGigsItem', $agetGigsItem);
}
i also try foreach loop but unable to resolve this issue.
foreach ($agetGigsItem as $key => $value) {
if ($value["Gig"]["rating"] == 0) { unset($agetGigsItem[$key]); }
}
I think you need to reupdate your array.
foreach ($agetGigsItem as $key => $value) {
if ($value["Gig"]["rating"] != 0)
{
unset($agetGigsItem[$key]);
}
$this->set('agetGigsItem', $agetGigsItem);
}
I hope you are missing $this and so you cannot access the array in CakePHP.
So try this:
foreach ($this->$agetGigsItem as $key => $value) {
if ($value["Gig"]["rating"] == 0) {
unset($this->$agetGigsItem[$key]);
}
}
This code will unset arrey index with value 0.
<?php
$array=array(
array(
'Gig' => array(
'id' => '1',
'rating' =>5
)
),
array(
'Gig' => array(
'id' => '3',
'rating' =>9
)
),
array(
'Gig' => array(
'id' => '4',
'rating' =>0
)
)
);
foreach($array as $a){
if($a['Gig']['rating']==0){
unset($a['Gig']['rating']);
}
$array1[]=$a;
}
var_dump($array1);
Destroying occurances within an array you are actually processing over with a for or a foreach is always a bad idea. Each time you destroy an occurance the loop can easily get corrupted and get in a terrible mess.
If you want to remove items from an array it is better to create a copy of the array and process over that new array in the loop but remove the items from the original array.
So try this instead
$tmparray = $this->agetGigsItem; // will copy agetGigsItem into new array
foreach ($tmparray as $key => $value) {
if ($value["Gig"]["rating"] == 0) {
unset($this->agetGigsItem[$key]);
}
}
unset($tmparray);

Categories