Flattening multidimensional array created by json_decode - php

I'm trying to flatten a multidimensional array that was returned by json_decode() but I'm having issues. I've some research but all of the solutions seem to be skipping over some of my data. If I run this and compare the echo'd data to var_dump() I'm definitely not getting everything and I'm not sure why.
Here is what I have so far:
<?php
function array_flatten($array) {
if (!is_array($array)) {
return false;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, array_flatten($value));
} else {
$result[$key] = $value;
}
}
return $result;
}
for ($x = 1; $x <= 1; $x++) {
$response = file_get_contents('https://seeclickfix.com/api/v2/issues?page='.$x
.'&per_page=1');
// Decode the JSON and convert it into an associative array.
$jsonDecoded = json_decode($response, true);
$flat = array_flatten($jsonDecoded['issues']);
foreach($flat as $item) {
echo $item;
echo "<br>";
}
}
?>

array_merge will overwrite values with the same key, as you can see in the documentation. E.g. in the link you posted, you will lose some urls. You could fix that by create unique keys in the flattened array. For example by passing a prefix to your function:
function array_flatten($array, $prefix = '') {
if (!is_array($array)) {
return false;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, array_flatten($value, $prefix.'_'.$key));
} else {
$result[$prefix.'_'.$key] = $value;
}
}
return $result;
}

Related

How to check given value present in nested array in PHP?

I am very new to the PHP, i want to check the value is present inside the associative array,please help me to acheive this thing.
public $array=[
'id','name',
'value.details'=>['type'=>'myFunction']
];
foreach($array as $key=>$condition){
if(in_array('myFunction',$array)){
//My logic
}
}
if you know the keys:
if($array['value.details']['type'] === 'myFunction') { }
if you walk through your array:
foreach($array as $key=>$val) {
if(is_array($val) && in_array('myFunction', $val)) {
//
}
}
Your array is mix of string and array, you might also wanna check the array inside your array.
$array=[
'id','name',
'value.details'=>['type'=>'myFunction']
];
$query = 'myFunction';
$isPresent = false;
foreach ($array as $data) {
if (gettype($data) === "array") {
foreach ($data as $val) {
if ($val === $query) {
$isPresent = true;
continue;
}
}
} else {
if ($query === $data) {
$isPresent = true;
continue;
}
}
}

Multi-imensional Array based on Keys

Is there a simple way to take a single-dimensional array and convert it to a multi-dimensional array based on the spaces, or any character(s), in the keys?
$arr['foo1'] = 'bar1';
$arr['foo2'] = 'bar2';
$arr['foo3 tier1' ] = 'bar3';
$arr['foo4 tier1' ] = 'bar4';
and turn it into
$arr['foo1'] = 'bar1';
$arr['foo2'] = 'bar2';
$arr['foo3']['tier1'] = 'bar3';
$arr['foo4']['tier1'] = 'bar4';
you can always do some sort of foreach loop
$newarr = array();
foreach ($arr as $key => $value) {
$output = explode(' ',$key,2);
if(count($output)) {
$newarr[$output[0]][$output[1]] = $value;
} else {
$newarr[$key] = $value;
}
}
That code will only work for one space but you can expand it to multiple spaces, something like
function pivot($arr,$delimeter) {
$return = array();
foreach ($arr as $key => $value) {
$output = explode($delimeter,$key,2);
if(count($output)) {
if(strpos($output[1],$delimeter) > 0) {
$return[$output[0]] = pivot(array($output[1]=>$value),$delimeter);
} else {
$return[$output[0]][$output[1]] = $value;
}
} else {
$return[$key] = $value;
}
}
return $return;
}

merge many array based on a common key php

I wasn't so clear in my first question, so i deleted it and here is a reformulation;
I have those arrays:
$open = array(array("FAI1","34"),array("FAI2","34"),array("FAI3","34"));
$click = array(array("FAI2","52"),array("FAI1","68"),array("FAI3","99"));
$unsubscribe = array(array("FAI2","103"),array("FAI3","67"),array("FAI1","102"));
$def_sent = array(array("FAI1","34",24),array("FAI2","34",23),array("FAI3","34",27));
$SB = array(array("FAI2","103"),array("FAI3","67"),array("FAI1","102"));
$HB = array(array("FAI2","103"),array("FAI3","67"),array("FAI1","102"));
I searched for a function to merge them and get a result like this:
$result = array(array("FAI1",34,68,102,34,24,102,102)
,array("FAI2","34",23.....),
array("FAI3","34",27....));
and to do this, i used the function, in the php online documentation, and this is the function
function array_merge_recursive() {
$arrays = func_get_args();
$base = array_shift($arrays);
foreach ($arrays as $array) {
reset($base);
while (list($key, $value) = #each($array)) {
if (is_array($value) && #is_array($base[$key])) {
$base[$key] = array_merge_recursive($base[$key], $value);
} else {
$base[$key] = $value;
}
}
}
return $base;
}
But instead of getting the result above i got this:
FAI1|34
FAI2|34
FAI3|34
FAI2|52
FAI1|68
FAI3|99
...
So i need some help to reformulate this function to get the expected result.
Try this function:
function array_merge_rec() {
$arrays = func_get_args();
$result = array();
foreach ($arrays as $arg) {
if (is_array($arg)) {
foreach ($arg as $item) {
if (!isset($result[$item[0]])) {
$result[$item[0]] = $item;
} else {
$result[$item[0]][] = $item[1];
}
}
} else {
echo "$arg skippend because it isn't array\n";
}
}
return array_values($result);
}
Does it help?

PHP Flatten Array with multiple leaf nodes

What is the best way to flatten an array with multiple leaf nodes so that each full path to leaf is a distinct return?
array("Object"=>array("Properties"=>array(1, 2)));
to yield
Object.Properties.1
Object.Properties.2
I'm able to flatten to Object.Properties.1 but 2 does not get processed with recursive function:
function flattenArray($prefix, $array)
{
$result = array();
foreach ($array as $key => $value)
{
if (is_array($value))
$result = array_merge($result, flattenArray($prefix . $key . '.', $value));
else
$result[$prefix . $key] = $value;
}
return $result;
}
I presume top down will not work when anticipating multiple leaf nodes, so either need some type of bottom up processing or a way to copy array for each leaf and process (althought that seems completely inefficient)
function flatten(array $data, $separator = '.') {
$result = array();
$stack = array();
$path = null;
reset($data);
while (!empty($data)) {
$key = key($data);
$element = $data[$key];
unset($data[$key]);
if (is_array($element)) {
if (!empty($data)) {
$stack[] = array($data, $path);
}
$data = $element;
$path .= $key . $separator;
} else {
$result[$path . $key] = $element;
}
if (empty($data) && !empty($stack)) {
list($data, $path) = array_pop($stack);
}
}
return $result;
}
var_dump(flatten(array("Object"=>array("Properties"=>array(1, 2)))));
Output:
array(2) {
["Object.Properties.0"]=>
int(1)
["Object.Properties.1"]=>
int(2)
}
Use function flatMapAssoc() from Kdyby Framework:
$flattened= array();
flatMapAssoc($array, function ($value, $keys) use (&$flattened) {
$flattened[implode('.', $keys)] = $value;
});
/**
* #param array|\Traversable $array
* #param callable $callback
* #return array
*/
function flatMapAssoc($array, $callback)
{
$callback = callback($callback);
$result = array();
$walker = function ($array, $keys = array()) use (&$walker, &$result, $callback) {
foreach ($array as $key => $value) {
$currentKeys = $keys + array(count($keys) => $key);
if (is_array($value)) {
$walker($value, $currentKeys);
continue;
}
$result[] = $callback($value, $currentKeys);
}
return $result;
};
return $walker($array);
}
I would use a wrapper function to hide implementation details (the prefix parameter)
and added an if branch to test for empty arrays. At last, in case of simple leaf you should use the $value variable and not the $key one.
$x = array("Object"=>array("Properties"=>array(1, 2), "test"=>array(), "post"));
function flatten ($array) {
return flattenArray('',$array);
}
function flattenArray($prefix, $array) {
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
if(count($value)) {
$result = array_merge($result, flattenArray($prefix."$key.", $value));
} else {
$result[] = "$prefix$key";
}
} else {
$result[] = "$prefix$value";
}
}
return $result;
}
echo join("\n", flatten($x));
If you want to mimic a tree structure, maybe you can use a different array structure. Something like this:
$y = array ("Object",
array("Properties", 1, 2),
"test",
"post"
);
and flattenArray becomes:
function flattenArray($prefix, $array) {
$result = array();
$prefix .=array_shift($array).'.';
foreach ($array as $value) {
if (is_array($value)) {
$result = array_merge($result, flattenArray($prefix, $value));
} else {
$result[] = "$prefix$value";
}
}
return $result;
}

PHP function to get recursive path keys with path

Given an array, I would like a flattened version of the array keys. Each array key would need the 'path' of the array, to that point, appended with an underscore.
An example explains this best.
$arr = array("location"=>0,"details"=>array("width"=>0,"height"=>0,"level"=>array("three"=>0)));
function answer($arr) {....}
the answer function would return this:
array("location","details_width","details_height","details_level_three");
UPDATE:
Here is the work in progress. It will accept an array and return the array keys, but with no depth:
function recursive_keys($input)
{
$output = array_keys($input);
foreach($input as $sub){
if(is_array($sub)){
$output = array_merge($output, recursive_keys($sub));
}
}
return $output;
}
$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
$results = array();
foreach ($ritit as $leafValue) {
$path = array();
foreach (range(0, $ritit->getDepth()) as $depth) {
$path[] = $ritit->getSubIterator($depth)->key();
}
$results[] = join('_', $path);
}
function recursive_keys(array $array, array $path = array()) {
$result = array();
foreach ($array as $key => $val) {
$currentPath = array_merge($path, array($key));
if (is_array($val)) {
$result = array_merge($result, recursive_keys($val, $currentPath));
} else {
$result[] = join('_', $currentPath);
}
}
return $result;
}
Demo here: http://codepad.viper-7.com/WQ3UYI

Categories