I am trying to created nested array from flat based on its keys.
Also format of keys in original array can be changed if it will simplify task.
From :
$arr = [
'player.name' => 'Joe',
'player.lastName' => 'Snow',
'team.name' => 'Stars',
'team.picture.name' => 'Joe Snow Profile',
'team.picture.file' => 'xxx.jpg'
];
To:
$arr = [
'player' => [
'name' => 'Joe'
, 'lastName' => 'Snow'
]
,'team' => [
'name'=> 'Stars'
,'picture' => [
'name' => 'Joe Snow Profile'
, 'file' =>'xxx.jpg'
]
],
];
Here is my take on it.
It should be able to handle arbitrary depth
function unflatten($arr) {
$result = array();
foreach($arr as $key => $value) {
$keys = explode(".", $key); //potentially other separator
$lastKey = array_pop($keys);
$node = &$result;
foreach($keys as $k) {
if (!array_key_exists($k, $node))
$node[$k] = array();
$node = &$node[$k];
}
$node[$lastKey] = $value;
}
return $result;
}
Combination of iteration and recursion. Could be simplified to just iterative.
$array = [
'player.name' => 'Joe',
'player.lastName' => 'Snow',
'team.name' => 'Stars',
'team.picture.name' => 'Joe Snow Profile',
'team.picture.file' => 'xxx.jpg'
];
$newArray = array ();
foreach($array as $key=> $value) {
$temp = array ();
$keys = array_reverse (explode('.', $key));
$temp[$keys[0]] = $value;
for ($i = 1; $i < count($keys); $i++) {
$temp[$keys[$i]] = $temp;
unset ($temp [$keys [$i -1]]);
}
$newArray = array_merge_recursive($newArray,$temp);
}
var_dump($newArray );
I received this question as a test, this is my answer:
<?php
function buildArray(&$newArray, $keys, $value)
{
if (sizeof($keys) == 0) {
return $value;
} else {
$key = array_shift($keys);
if (isset($newArray[$key])) {
$value = buildArray($newArray[$key], $keys, $value);
if (is_array($value)) {
$newArray[$key] += $value;
} else {
$newArray[$key] = $value;
}
$arr = $newArray;
} else {
$arr[$key] = buildArray($newArray, $keys, $value);
}
}
return $arr;
}
$arr = [
'player.name' => 'Joe',
'player.lastName' => 'Snow',
'team.name' => 'Stars',
'team.picture.name' => 'Joe Snow Profile',
'team.picture.file' => 'xxx.jpg',
];
$newArray = [];
foreach ($arr as $key => $value) {
$explodedKey = explode(".", $key);
$temp = buildArray($newArray, $explodedKey, $value);
$newArray = array_merge($temp, $newArray);
}
print_r($newArray);
?>
You could do it like this
$newArr = [];
for ($arr as $key => $val) {
$tmp = explode ('.', $key);
if (!array_key_exists ($tmp [0], $newArray){
$newArray [$tmp [0]] = [];
}
$newArray [$tmp [0]][$tmp [1]] = $val;
}
edit:
Damn didn't saw the third level in team.
Not very generic but should work for third level ;)
$newArr = [];
for ($arr as $key => $val) {
$tmp = explode ('.', $key);
if (!array_key_exists ($tmp [0], $newArray){
$newArray [$tmp [0]] = [];
}
if (count($tmp) > 2){
if (!array_key_exists ($tmp [1], $newArray[$tmp [0]]){
$newArray [$tmp [0]][$tmp[1]] = [];
}
$newArray [$tmp [0]][$tmp [1]][$tmp [2]] = $val;
} else {
$newArray [$tmp [0]][$tmp [1]] = $val;
}
}
I think you can use something like this, for converting 2d array to nested tree. But You'll have to play with parent_id
https://github.com/denis-cto/flat-array-to-nested-tree
Related
So I have the following array:
$array = array(array('fruit1' => 'apple'),
array('fruit2' => 'orange'),
array('veg1' => 'tomato'),
array('veg2' => 'carrot'));
and I want to run a function like this:
array_remove_recursive($array, 'tomato');
so the output is this:
$array = array(array('fruit1' => 'apple'),
array('fruit2' => 'orange'),
array('veg2' => 'carrot')); // note: the entire array containing tomato has been removed!
Is this solvable?
This will recursively unset the matching variable at any depth and then remove the parent element only if it is empty.
function recursive_unset(array &$array, $unwanted_val) {
foreach ($array as $key => &$value) {
if (is_array($value)) {
recursive_unset($value, $unwanted_val);
if(!count($value)){
unset($array[$key]);
}
} else if($value == $unwanted_val){
unset($array[$key]);
}
}
}
Function to remove recursively many values from multidimensional array.
# Example 1
$arr1 = array_remove_recursive($arr, 'tomato');
# Example 2
$arr2 = array_remove_recursive($arr, ['tomato', 'apple']);
function array_remove_recursive($arr, $values)
{
if (!is_array($values))
$values = [$values];
foreach ($arr as $k => $v) {
if (is_array($v)) {
if ($arr2 = array_remove_recursive($v, $values))
$arr[$k] = $arr2;
else
unset($arr[$k]);
} elseif (in_array($v, $values, true))
unset($arr[$k]);
}
return $arr;
}
function array_remove_recursive($getArray,$getAssocValue)
{
$returnArray = array();
if(is_array($getArray))
{
foreach($getArray as $indAssocValue)
{
if(is_array($indAssocValue))
{
foreach($indAssocValue as $innerKey=>$innerVal)
{
if($innerVal!=$getAssocValue and $innerKey!="")
{
$returnArray[] = array("$innerKey"=>$innerVal);
}
}
}
}
}
return $returnArray;
}
$array = array(array('fruit1' => 'apple'),
array('fruit2' => 'orange'),
array('veg1' => 'tomato'),
array('veg2' => 'carrot'));
print_r($array);
echo "<br />";
$array = array_remove_recursive($array, 'tomato');
print_r($array);
hope the above code would be helpfull.
I have an array like this one :
Array
{
'property1.subproberty11' => "xxxxx",
'property1.subproberty12' => "yyyy",
'property2.subproberty21.subproperty211' => "zzzzzz",
'property2.subproberty21.subproperty212' => "wwwww",
'property2.subproberty22' => "yyyy",
....
That needs to be changed into something like :
Array
(
[property1] => Array
(
['subproberty11'] => "xxxxx"
['subproberty12'] => "yyyy"
)
[property2] => Array
(
[subproperty21] => Array
(
[subproperty211] => "zzzzzz"
[subproperty212] => "wwwwww"
)
['subproberty22'] => "yyyy"
)
...
I can't find a smart way of doing this, can someone help me ?
So, far, i have thought of this kind of algorithm :
$new_array = array();
foreach($old_array as $key => $value)
{
$subkeys = explode('.', $key);
$ss = array();
for($ii = 0 ; $ii < count($subkeys) ; $ii++)
{
$ss[] = "['".$subkeys[$ii]."']";
if ($ii < count($subkeys) -1)
eval('$new_array'.implode('',$ss).' = array();');
}
eval('$new_array'.implode('',$ss)." = '".$value."';');
}
I think we can do better, for example maybe we can avoid duplicating data by creating a new array ?
My working example:
function nestedKeysArray($input) {
$array = array();
foreach ($input as $key => $value) {
$keys = explode('.', $key);
if (count($keys) == 1) {
$array[$key] = $value;
} else {
$nested = &$array;
foreach ($keys as $k) {
if (!isset($nested[$k]))
$nested[$k] = array();
$nested = &$nested[$k];
}
$nested = $value;
}
}
return $array;
}
$input is array like first one from the question.
EDIT:
Changing original array, without copy:
function nestedKeysArray(&$input) {
foreach ($input as $key => $value) {
$keys = explode('.', $key);
if (count($keys) > 1) {
$nested = &$input;
foreach ($keys as $k) {
if (!isset($nested[$k]))
$nested[$k] = array();
$nested = &$nested[$k];
}
$nested = $value;
unset($input[$key]);
}
}
}
Some untested code, to give you the direction you could take.
Just loop through the array;
function SplitArray($properties) {
foreach($properties as $item=>$property) {
$properties[$item] = explode('.',$property, 2);
if(strpos($properties[$item][1], '.') === false)) {}
else {
$properties[$item][1] = SplitArray($properties[$item][1]);
}
}
return $properties;
}
I came up with this ugly verbose array (and I have to use it):
$puppy_mother_father_arr = array(
array('46' => array('30','29')),
array('17' => array('30','29')),
array('16' => array('24','29'))
);
How do I simplify it to something like this :
$puppy_mother_father_arr = array(
'46' => array('30','29'),
'17' => array('30','29'),
'16' => array('24','29')
);
I've been stuck a day in here. thanks in advance
$tmp = array();
foreach ($puppy_mother_father_arr as $parent) {
foreach($parent as $key => $nodes) {
$tmp[$key] = $nodes;
}
}
$puppy_mother_father_arr = $tmp;
Would this work?
See the result online
<?php
$puppy_mother_father_arr = array( array('46' => array('30','29')),array('17' => array('30','29')),array('16' => array(24,'29')) );
$list = array();
foreach ($puppy_mother_father_arr as $info)
{
foreach ($info as $key => $value)
{
$list[$key] = $value;
break;
}
}
var_export($list);
$newarray = array();
foreach ($puppy_mother_father_arr as $array) {
foreach ($array as $puppy => $parents) {
$newarray[$puppy] = $parents;
}
}
$puppy_mother_father_arr = $newarray;
key and current could be useful if each array has only one interested key and value:
$result = array();
foreach($puppy_mother_father_arr as $arr) {
$result[key($arr)] = current($arr);
}
var_dump($result);
$result = array_merge($arr1,$arr2);
I want to exclude numerical values of $arr2,is there an option for this?
Edit after comment:
$arr1 = array('key' => 1);
$arr2 = array('test',1 => 'test', 'key2' => 2);
after processing I need the result to be:
array('key' => 1,'key2' => 2);
Excluding numerical keys
It seems that you want to array_filter your $arr2's keys, first:
function not_numeric( $object ) {
return !is_numeric( $object );
}
$no_numeric_keys = array_filter( array_keys( $arr2 ), not_numeric );
$no_numeric_array = array_intersect_keys( $arr2, $no_numeric_keys );
$result = array_merge( $arr1, $no_numeric_array );
I'm guessing that this would work, after using $result = array_merge($arr1,$arr2);:
foreach ($result as $key => $value) {
if (is_numeric($key)) {
unset($result[$key]);
}
}
Edit:
In as few lines as possible (1) – as requested in the new title:
foreach ($result as $key => $value) { if (is_numeric($key)) { unset($result[$key]); } }
Just loop through each array and test if keys are strings:
$output = array();
foreach($arr1 as $key => $value) {
if(is_string($key)) {
$output[$key] = $value;
}
}
foreach($arr2 as $key => $value) {
if(is_string($key)) {
$output[$key] = $value;
}
}
Edit:
Since you said elegant...
function merge_arrays_string_keys()
{
$output = array();
foreach(func_get_args() as $arr)
{
if(is_array($arr))
{
foreach($arr as $key => $value) {
if(is_string($key) {
$output[$key] = $value;
}
}
}
}
return $output;
}
elegant, huh?
$test = array('test', 1 => 'test', 'key2' => 2, 33, 3 => 33, 'foo' => 'bar');
$test_non_num = array_intersect_key(
$test,
array_flip(
array_diff(
array_keys($test),
array_filter(array_keys($test), 'is_int'))));
print_r($test_non_num); // key2=>2, foo=>bar
Use this code , it will also do the require thing.
<?php
$result = array ( 1,"pavunkumar","bks", 123 , "3" ) ;
array_walk($result,'test_print');
print_r ( $result ) ;
function test_print( $val , $key )
{
global $result;
if ( gettype ( $val ) == 'integer' )
{
unset ( $result[$key] ) ;
}
}
array_diff_ukey($m=$arr2+$arr1,$m,function($k){return is_string($k);})
In an array such as the one below, how could I rename "fee_id" to "id"?
Array
(
[0] => Array
(
[fee_id] => 15
[fee_amount] => 308.5
[year] => 2009
)
[1] => Array
(
[fee_id] => 14
[fee_amount] => 308.5
[year] => 2009
)
)
foreach ( $array as $k=>$v )
{
$array[$k] ['id'] = $array[$k] ['fee_id'];
unset($array[$k]['fee_id']);
}
This should work
You could use array_map() to do it.
$myarray = array_map(function($tag) {
return array(
'id' => $tag['fee_id'],
'fee_amount' => $tag['fee_amount'],
'year' => $tag['year']
); }, $myarray);
$arrayNum = count($theArray);
for( $i = 0 ; $i < $arrayNum ; $i++ )
{
$fee_id_value = $theArray[$i]['fee_id'];
unset($theArray[$i]['fee_id']);
$theArray[$i]['id'] = $fee_id_value;
}
This should work.
Copy the current 'fee_id' value to a new key named 'id' and unset the previous key?
foreach ($array as $arr)
{
$arr['id'] = $arr['fee_id'];
unset($arr['fee_id']);
}
There is no function builtin doing such thin afaik.
This is the working solution, i tested it.
foreach ($myArray as &$arr) {
$arr['id'] = $arr['fee_id'];
unset($arr['fee_id']);
}
The snippet below will rename an associative array key while preserving order (sometimes... we must). You can substitute the new key's $value if you need to wholly replace an item.
$old_key = "key_to_replace";
$new_key = "my_new_key";
$intermediate_array = array();
while (list($key, $value) = each($original_array)) {
if ($key == $old_key) {
$intermediate_array[$new_key] = $value;
}
else {
$intermediate_array[$key] = $value;
}
}
$original_array = $intermediate_array;
Converted 0->feild0, 1->field1,2->field2....
This is just one example in which i get comma separated value in string and convert it into multidimensional array and then using foreach loop i changed key value of array
<?php
$str = "abc,def,ghi,jkl,mno,pqr,stu
abc,def,ghi,jkl,mno,pqr,stu
abc,def,ghi,jkl,mno,pqr,stu
abc,def,ghi,jkl,mno,pqr,stu;
echo '<pre>';
$arr1 = explode("\n", $str); // this will create multidimensional array from upper string
//print_r($arr1);
foreach ($arr1 as $key => $value) {
$arr2[] = explode(",", $value);
foreach ($arr2 as $key1 => $value1) {
$i =0;
foreach ($value1 as $key2 => $value2) {
$key3 = 'field'.$i;
$i++;
$value1[$key3] = $value2;
unset($value1[$key2]);
}
}
$arr3[] = $value1;
}
print_r($arr3);
?>
I wrote a function to do it using objects or arrays (single or multidimensional) see at https://github.com/joaorito/php_RenameKeys.
Bellow is a simple example, you can use a json feature combine with replace to do it.
// Your original array (single or multi)
$original = array(
'DataHora' => date('YmdHis'),
'Produto' => 'Produto 1',
'Preco' => 10.00,
'Quant' => 2);
// Your map of key to change
$map = array(
'DataHora' => 'Date',
'Produto' => 'Product',
'Preco' => 'Price',
'Quant' => 'Amount');
$temp_array = json_encode($original);
foreach ($map AS $k=>$v) {
$temp_array = str_ireplace('"'.$k.'":','"'.$v.'":', $temp);
}
$new_array = json_decode($temp, $array);
Multidimentional array key can be changed dynamically by following function:
function change_key(array $arr, $keySetOrCallBack = [])
{
$newArr = [];
foreach ($arr as $k => $v) {
if (is_callable($keySetOrCallBack)) {
$key = call_user_func_array($keySetOrCallBack, [$k, $v]);
} else {
$key = $keySetOrCallBack[$k] ?? $k;
}
$newArr[$key] = is_array($v) ? array_change_key($v, $keySetOrCallBack) : $v;
}
return $newArr;
}
Sample Example:
$sampleArray = [
'hello' => 'world',
'nested' => ['hello' => 'John']
];
//Change by difined key set
$outputArray = change_key($sampleArray, ['hello' => 'hi']);
//Output Array: ['hi' => 'world', 'nested' => ['hi' => 'John']];
//Change by callback
$outputArray = change_key($sampleArray, function($key, $value) {
return ucwords(key);
});
//Output Array: ['Hello' => 'world', 'Nested' => ['Hello' => 'John']];
I have been trying to solve this issue for a couple hours using recursive functions, but finally I realized that we don't need recursion at all. Below is my approach.
$search = array('key1','key2','key3');
$replace = array('newkey1','newkey2','newkey3');
$resArray = str_replace($search,$replace,json_encode($array));
$res = json_decode($resArray);
On this way we can avoid loop and recursion.
Hope It helps.