This question already has answers here:
PHP recursive array searching
(3 answers)
Closed 2 years ago.
That's a short version of the array I'm working with:
Array
(
[orders] => Array
(
[0] => Array
(
[id] => 123
[email] => somemail#mail.com
[line_items] => Array
(
[0] => Array
(
[id] => 456
)
)
)
)
)
I'd like to loop through it and echo out every $key => $value pair but keep track of the "parent" array.
When using this function:
function recursive($array, $level = 0){
foreach($array as $key => $value){
if(is_array($value)){
recursive($value, $level + 1);
} else{
echo $key . ": " . $value, "\n";
}
}
}
i get:
id: 123
email: somemail#mail.com
id: 456
and I would like to keep the parent array in front of the values so that i know which id is echoed out.
orders_0_id: 123
orders_0_email: somemail#mail.com
line_items_0_id: 456
Updated working solution:
function recursive($array, $level = -1,array $parentKey = []){
foreach($array as $key => $value){
$newKey = array_merge($parentKey, [$key]);
if(is_array($value)){
recursive($value, $level + 1, $newKey);
} else{
$parent = implode('_', $newKey);
echo $parent . ": " . $value, "\n";
}
}
}
I think this is what you are looking for, but it might be too much information.
Given this array:
$data = [
'orders' => [
[
'id' => 123,
'email' => 'text#example.com',
'line_items' => [
[
'id' => 356,
],
],
],
],
];
You can keep track of the parent key in an array:
function dumper(array $array, array $parentKey = [])
{
foreach ($array as $key => $value) {
$newKey = array_merge($parentKey, [$key]);
if (is_array($value)) {
dumper($value, $newKey);
} else {
$s = implode('_', $newKey) . ": " . $value . "\n";
echo $s . PHP_EOL;
}
}
}
dumper($data);
This produces:
orders_0_id: 123
orders_0_email: text#example.com
orders_0_line_items_0_id: 356
Related
This question already has answers here:
How to implode array with key and value without foreach in PHP
(13 answers)
Closed 8 months ago.
I have this array
Array ( [13] => 500 [16] => 1000 )
Array ( [12] => 1 [13] => 1111 )
how can I make them a string as this shape
13 500, 16 1000
12 1, 13 1111
Using implode and array_map
$input = [13 => 500, 16 => 1000];
$output = implode(', ', array_map(
function ($v, $k) {
return $k . " " . $v;
}, $input, array_keys($input))
);
var_dump($output);
Using foreach
$input = [13 => 500, 16 => 1000];
$output = "";
foreach ($input as $k => $v) {
$output .= $k . " " . $v . ", ";
}
$output = rtrim($output, ", ");
var_dump($output);
This code will solve your issue.
$array = array("Peter"=>"35", "Ben"=>"37", "Joe"=>"43");
foreach ($array as $key => $val) {
echo " ".$key ." ". $val." ,";
}
assuming you searching for a function with multiple pair array values (as you describe)
and each result should be the format: key1[sp]val1,[sp]key2[sp]val2 and you want an array of all these values to use later i did this function:
<?php
function ar(){
$a=func_get_args();
foreach($a as $ar){
$s='';
$i=0;
$s='';
foreach($ar as $ch =>$vl){
$s.=$ch.' '.$vl;
if($i<count($ar)-1){
$s.=', ';
}
$i++;
}
$res[]=$s;
}
return $res;
}
/* output values by sending multiple arrays to parse */
var_dump(ar(
[13 => 500,16=> 1000]
,[12 => 1,13 => 1111]
));
?>
I have this problem with my code converting my multidimensional array to csv.
This is the structure of my array
Array (
[vbas31] =>
Array ( [enabled] => Array ( [0] => NO )
[registered] => Array ( [0] => NO ) )
[bnmsa1] =>
Array ( [enabled] => Array ( [0] => YES )
[registered] => Array ( [0] => NO )
[compromised] => Array ( [0] => NO ) )
)
and I want to save it to a csv file for reporting purposes, like this:
vbas31, enabled, no, registered, no
bnmsa1, enabled, yes, registered, no, compromised, no
What I did in my code is something like this:
$file = fopen('testfile.csv','w');
$keysarr = array_keys($jsonArr);
for($i = 0; $i < count($jsonArr); $i++) {
foreach($jsonArr[$keysarr[$i]] as $key => $value) {
echo $key . " : " . $value[0] . "<br>";
}
$new_line = [$keysarr[$i], $key, $value[0]];
fputcsv($file, $new_line);
}
fclose($file);
But the output is not what I want, and here's the output that is generated by my code:
vbas31, registered, no
bnmsa1, compromised, no
It only gets the last data from the array. Can I ask what's the problem with my code and what I'm doing wrong?
I'm not a fan of nested loops, as well as provided answers but look at this:
Your array:
$yourArray = [
'bnas31' => [
'enabled' => [0 => 'NO'],
'registered' => [0 => 'NO']
],
'bnmsa1' => [
'enabled' => [0 => 'YES'],
'registered' => [0 => 'NO'],
'compromised' => [0 => 'NO']
]
];
Code:
foreach($yourArray as $key1 => $value1) {
$row = $key1;
$line = [$key1];
foreach ($value1 as $key2 => $value2) {
$row .= ','.$key2.','.$value2[0];
$line = array_merge($line, [$key2, $value2[0]]);
}
echo $row.'<br>';
}
You can use another foreach inside your other foreach. :)
You can just add the key first to the new line, and then iterate on rest of the elements and add those as well.
The $row variable is just for checking the result.
The code is so simple you should be able to analyze it by yourself.
The result of the above code is:
bnas31,enabled,NO,registered,NO
bnmsa1,enabled,YES,registered,NO,compromised,NO
Greetings.
what's the problem with my code and what I'm doing wrong?
Your code is only saving the last element of each nested array because your fputcsv() is only happening for the last element of that nested array - it happens outside that last, inner loop. Move it inside, where your echo is, and it will work.
for($i = 0; $i < count($jsonArr); $i++) {
foreach($jsonArr[$keysarr[$i]] as $key => $value) {
// Inside inner loop - this works
// echo $keysarr[$i] . ": " . $key . ", " . $value[0] . "\n";
}
// Outside inner loop - only shows last element because we only
// get here after the inner loop over the nested array has
// finished. At that time the variables are set to whatever
// they were at the end of the last iteration - the last element.
echo $keysarr[$i] . ": " . $key . ", " . $value[0] . "\n";
}
Having said that, your looping is a bit more complicated than it needs to be, here's a simpler version, and a working example:
$file = fopen('testfile.csv','w');
foreach ($jsonArr as $index => $data) {
foreach ($data as $key => $array) {
// Some debug output
echo $index . ": " . $key . ", " . $array[0] . "\n";
// And save your line
$line = [$index, $key, $array[0]];
fputcsv($file, $line);
}
}
fclose($file);
I'm trying to get an xml file from an associative array having array keys encapsuled into '<' and '>'
I've tried to use a recursive function but it works correctly only on the first level:
Please remember my final goal is to create an xml, so any appropriate suggest is welcome
this is what I've done so far:
$arr =
array('<Lev0_0>' => 0,
'<Lev0_1>' => 1,
'<Lev0_2>' => array (
'<Lev1_0>' => 2,
'<Lev1_1>' => 3
)
);
print_r(RepairKeysMultidimensional($arr));
function RepairKeysMultidimensional(array $array){
$Keys = array();
foreach($array as $Key => $Value){
$NewKey = str_replace(array('<','>'),'',$Key);
$array[$NewKey] = $Value;
unset($array[$Key]);
if(is_array($Value)){
RepairKeysMultidimensional($Value);
}
}
return $array;
}
the output is:
Array (
[Lev0_0] => 0
[Lev0_1] => 1
[Lev0_2] => Array (
[] => 2
[] => 3
)
)
If that's the structure and you never expect < or > as part of the values, you don't need to loop over it just json_encode it, strip out the chars and the json_decode it back into an array.
<?php
$arr = array(
'<Lev0_0>' => 0,
'<Lev0_1>' => 1,
'<Lev0_2>' => array (
'<Lev1_0>' => 2,
'<Lev1_1>' => 3
)
);
$arr = json_decode(str_replace(array('<','>'), '', json_encode($arr)), true);
print_r($arr);
https://3v4l.org/2d7Hq
Result:
Array
(
[Lev0_0] => 0
[Lev0_1] => 1
[Lev0_2] => Array
(
[Lev1_0] => 2
[Lev1_1] => 3
)
)
Try to add affectation in your if statement:
function RepairKeysMultidimensional(array $array){
$Keys = array();
foreach($array as $Key => $Value){
$NewKey = str_replace(array('<','>'),'',$Key);
$array[$NewKey] = $Value;
unset($array[$Key]);
if (is_array($Value)) {
$array[$NewKey] = RepairKeysMultidimensional($Value);
}
}
return $array;
}
you are not affecting the result of the second call to the outer array!
Try this :
<?php
$arr =
array('<Lev0_0>' => 0,
'<Lev0_1>' => 1,
'<Lev0_2>' => array (
'<Lev1_0>' => 2,
'<Lev1_1>' => 3
)
);
echo str_replace(array('<','>'),'','<Lev0>');
echo '<br/><br/>';
print_r(RepairKeysMultidimensional($arr));
function RepairKeysMultidimensional(array $array){
$Keys = array();
foreach($array as $Key => $Value){
$NewKey = str_replace(array('<','>'),'',$Key);
unset($array[$Key]);
if(is_array($Value)){
$array[$NewKey] = RepairKeysMultidimensional($Value);
}else{
$array[$NewKey] = $Value;
}
}
return $array;
}
The output of this is :
Array (
[Lev0_0] => 0
[Lev0_1] => 1
[Lev0_2] => Array (
[Lev1_0] => 2
[Lev1_1] => 3 ) )
I am struggling to return values from all layers of a multidimensional array, e.g. value then all child elements. I've tried lots of loops but can't quite get it right. Please can someone help - I've been stuck for ages! Thank you.
The array is:
Array
(
[SiteRep] => Array
( [DV] => Array
(
[Location] => Array
(
[Period] => Array
(
[0] => Array
(
[value] => 2016-12-19Z
[Rep] => Array
(
[0] => Array
(
[D] => W
[F] => 1
[G] => 9
)
[1] => Array
(
[D] => W
[F] => 0
[G] => 7
)
)
)
[1] => Array
(
[value] => 2016-12-20Z
[Rep] => Array
(
[0] => Array
(
[D] => ENE
[F] => 4
[G] => 7
)
[1] => Array
(
[D] => E
[F] => 3
[G] => 9
)
so far my code is:
$i=0;
foreach ($json_decoded['SiteRep']['DV']['Location']['Period'][$i] as $key => $value) {
if (is_array($value)){
foreach ($value as $key2 => $value2){
if (is_array($value2)){
foreach ($value2 as $key3 => $value3) {
echo $key3 . " 3: " . $value3 . "<br>";
}
} else {
echo $key2 . " 2: " . $value2 . "<br>";
}
};
} else {
echo $key . " 1: " . $value . "<br>";
}
$i++;
};
I believe you are looking for recursion. A function that calls itself. It can be tricky but it is by far the most efficient way to navigate an array of indeterminate depth.
function printStuff($stuff)
{
echo $stuff['value']
if (isset($stuff['rep']))
{
printStuff($stuff['rep']);
}
}
If you want the values to pass down simply change echo to a return value:
function printStuff($stuff)
{
$temp = $stuff['value']
if (isset($stuff['rep']))
{
$temp .= printStuff($stuff['rep']);
}
return $temp;
}
Note: recursion can cause out of memory if not set up correctly similar to an infinite loop, as the recursive function call pushes the function call onto the call stack every time. Just make sure your function call has a subset of the parameter passed in.
If your array has the constantly number of layers, you may use foreach-function for the each layer. If your array has different number of layers every time - you should use the recursion, because it's the only solution in your situation.
Something like this:
array_walk_recursive($array, function($item, $key){
//your actions
});
I've continued drilling down and managed to get all the data I need by using...
foreach ($json_decoded['SiteRep']['DV']['Location']['Period'] as $key => $value) {
if (is_array($value)){
foreach ($value as $key2 => $value2){
if (is_array($value2)){
foreach ($value2 as $key3 => $value3) {
foreach ($value3 as $key4 => $value4) {
echo $key4 . ": " . $value4 . "<br>";
}
}
} else {
echo $key2 . ": " . $value2 . "<br>";
}
};
} else {
echo $key . ": " . $value . "<br>";
}
$i++;
};
This can map the array recursivly. Preserving they keys and structure.
You can however only return a new value and not change the key. But you will know which key you are looking at and if you just want to echo it you can do that to.
array_map_assoc_recursive('callback', $array)
function callback($key, $value) {
return "new" . $value;
}
function array_map_assoc_recursive($f, array $a) {
return array_column(array_map(function ($key, $value) use ($f) {
if (is_array($value)) {
return [$key, array_map_assoc_recursive($f, $value)];
} else {
return [$key, call_user_func($f, $key, $value)];
}
}, array_keys($a), $a), 1, 0);
}
I have an array in the format
Array
(
[/Callum/] => Array
(
[0] => ##chan1
)
[/Adam/] => Array
(
[0] => ##chan2
)
[/Chris)/] => Array
(
[0] => ##chan1
)
[/Mike*/] => Array
(
[0] => ##chan3
)
)
And from this I use the below code to try and get the id of the array that each channel features in.
foreach($array as $row)
{
if (in_array($buf['channel'],$row))
{
$return = $return." ".current(array_keys($array,$row));
}
}
My problem is that current() doesnt seem to work the way I am expecting it to. Currently if the $buf /Callum/ twice rather than /Callum/ and /Chris/
Why not:
foreach($array as $key => $row)
{
if (in_array($buf['channel'],$row))
{
$return = $return . " " . $key;
}
}
Try this instead
foreach($array is $id => $row){
$return .=" ".$id;
}
edit:
foreach($array is $id => $row){
if($row[0] == $buf['channel']){
echo $key; //This is your key
}
}