$arr_type=array(
"1"=>"A",
"2"=>"B",
"3"=>"C",
"4"=>"D",
"5"=>"E",
"6"=>"F",
"7"=>"G",
"8"=>"H"
);
how to change key name and level change?
$arr_type['1']['name'] = A;
$arr_type['2']['name'] = B;
$new_arr = array();
foreach($arr_type as $k => $v){
$new_arr[$k]['name'] = $v;
}
Since this got chosen, I'm also adding #Mark Baker's comment using array_walk here:
array_walk($arr_type, function (&$value) { $value = ['name' => $value]; });
In case one wants to keep the original array unchanged, this solution would also work:
$result = array_map(function ($value) { return ['name' => $value]; }, $arr_type);
Related
I have an array that looks like this.
$array = [
0 => 'abc',
1 => [
0 => 'def',
1 => 'ghi'
],
'assoc1' => [
'nassoc' => 'jkl',
'nassoc2' => 'mno',
'nassoc3' => '',
'nassoc4' => false
]
];
The $array can have numeric keys or be an assoc array or a mixed one. The level of nesting is not known. Also the values of the array can also be bool or null or an empty string ''
I need to able to convert this into a scalar array with key value pairs. And then later reconvert it back to the exact same array.
So the scalar array could look like
$arrayScalar = [
'0' => 'abc',
'1[0]' => 'def',
'1[1]' => 'ghi',
'assoc1[nassoc]' => 'jkl',
'assoc1[nassoc2]' => 'mno',
'assoc1[nassoc3]' => '',
'assoc1[nassoc4]' => false
];
And then later be able to get back to the initial $array.
I wrote a parser and it does not currently handle bool values correctly.
I have a feeling this is at best a super hacky method to do what I am after. Also I have been able to test it only so much.
function flattenNestedArraysRecursively($nestedArray, $parent = '', &$flattened = [])
{
$keys = array_keys($nestedArray);
if (empty($keys)) {
$flattened[$parent] = 'emptyarray';
} else {
foreach ($keys as $value) {
if (is_array($nestedArray[$value])) {
$reqParent = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$this->flattenNestedArraysRecursively($nestedArray[$value], $reqParent, $flattened);
} else {
$reqKey = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$flattened[$reqKey] = $nestedArray[$value];
}
}
}
return $flattened;
}
function reCreateFlattenedArray($flatArray): array
{
$arr = [];
foreach ($flatArray as $key => $value) {
$keys = explode('|!|', $key);
$arr = $this->reCreateArrayRecursiveWorker($keys, $value, $arr);
}
return $arr;
}
function reCreateArrayRecursiveWorker($keys, $value, $existingArr)
{
//Outside to Inside
$keyCur = array_shift($keys);
//Check if keyCur Exists in the existingArray
if (key_exists($keyCur, $existingArr)) {
// Check if we have reached the deepest level
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// If not then continue to go deeper while appending deeper levels values to current key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, $existingArr[$keyCur]);
return $existingArr;
}
} else {
// If Key does not exists in current Array
// Check deepest
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// Add the key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, []);
return $existingArr;
}
}
}
Is there a better more elegant way of doing this, maybe http_build_query or something else I am not aware of.
Sandbox link -> http://sandbox.onlinephpfunctions.com/code/50b3890e5bdc515bc145eda0a1b34c29eefadcca
Flattening:
Your approach towards recursion is correct. I think we can make it more simpler.
We loop over the array. if the value is an array in itself, we recursively make a call to this new child subarray.
This way, we visit each key and each value. Now, we are only left to manage the keys to assign them when adding to our final resultant array, say $arrayScalar.
For this, we make a new function parameter which takes the parent key into account when assigning. That's it.
Snippet:
$arrayScalar = [];
function flatten($array,&$arrayScalar,$parent_key){
foreach($array as $key => $value){
$curr_key = empty($parent_key) ? $key : $parent_key . '[' . $key . ']';
if(is_array($value)){
flatten($value,$arrayScalar,$curr_key);
}else{
$arrayScalar[$curr_key] = $value;
}
}
}
flatten($array,$arrayScalar,'');
var_export($arrayScalar);
Demo: http://sandbox.onlinephpfunctions.com/code/1e3092e9e163330f43d495cc9d4acb672289a987
Unflattening:
This one is a little tricky.
You might have already noticed that the keys in the flattened array are of the form key1[key2][key3][key4] etc.
So, we collect all these individually in a new array, say $split_key. It might look like this.
array (
'key1',
'key2',
'key3',
'key4',
)
To achieve the above, we do a basic string parsing and added in-between keys to the array whenever we reach the end of the key string or [ or ].
Next, to add them to our final resultant array, we loop over the collected keys and check if they are set in our final array. If not so, set them. We now pass child array reference to our temporary variable $temp. This is to edit the same copy of the array. In the end, we return the result.
Snippet:
<?php
function unflatten($arrayScalar){
$result = [];
foreach($arrayScalar as $key => $value){
if(is_int($key)) $key = strval($key);
$split_key = [];
$key_len = strlen($key);
$curr = '';
// collect them as individual keys
for($i = 0; $i < $key_len; ++$i){
if($key[ $i ] == '[' || $key[ $i ] == ']'){
if(strlen($curr) === 0) continue;
$split_key[] = $curr;
$curr = '';
}else{
$curr .= $key[ $i ];
}
if($i === $key_len - 1 && strlen($curr) > 0){
$split_key[] = $curr;
}
}
// collecting them ends
//add them to our resultant array.
$temp = &$result;
foreach($split_key as $sk){
if(!isset($temp[ $sk ])){
$temp[ $sk ] = [];
}
$temp = &$temp[$sk];
}
$temp = $value;
}
return $result;
}
var_export(unflatten($arrayScalar));
Demo: http://sandbox.onlinephpfunctions.com/code/66136a699c3c5285eed3d3350ed4faa5bbce4b76
I have a MYSQL query that fetches an array of dictionaries or results which are returned via JSON in an api. In some cases, I would like to change the name of the dictionary keys in the results array.
For example, in the following case:
$var = '[{"player":"Tiger Woods"},{"player":"Gary Player"}]';
I would like to change it to:
$var = '[{"golfer":"Tiger Woods"},{"golfer":"Gary Player"}]'
It is not practical in this case to change the mysql query so I'd just like to replace the word "player" with the word "golfer" for the keys without disturbing the values.
In the above example, I would not want to change Gary Player's name so just using str_replace does not seem like it would work.
Is there a way to change all of the keys from "player" to "golfer" without changing any of the values?
Here is the snippet you can use
$var = '[{"player":"Tiger Woods"},{"player":"Gary Player"}]';
// json decode the json string
$temp = json_decode($var, true);
$temp = array_map(function($item){
// combining key and values
return array_combine(['golfer'], $item);
}, $temp);
print_r($temp);
// or echo json_encode($temp);
Demo.
Some argue that foreach is fastest,
foreach($temp as $k => &$v){
$v = array_combine(['golfer'], $v);
}
print_r($temp);
Demo.
Little hardcoded if more than one keys in single array,
foreach ($temp as $k => &$v){
$v['golfer'] = $v['player'];
unset($v['player']);
}
print_r($temp);
Demo.
Using recursion
function custom($arr, $newKey, $oldKey)
{
// if the value is not an array, then you have reached the deepest
// point of the branch, so return the value
if (!is_array($arr)) {
return $arr;
}
$result = []; // empty array to hold copy of subject
foreach ($arr as $key => $value) {
// replace the key with the new key only if it is the old key
$key = ($key === $oldKey) ? $newKey : $key;
// add the value with the recursive call
$result[$key] = custom($value, $newKey, $oldKey);
}
return $result;
}
$var = '[{"player":"Tiger Woods"},{"player":"Gary Player"}]';
$temp = json_decode($var, true);
$temp = replaceKey($temp, 'golfer', 'player');
print_r($temp);
Demo & source.
Using json way,
function json_change_key($arr, $oldkey, $newkey) {
$json = str_replace('"'.$oldkey.'":', '"'.$newkey.'":', json_encode($arr));
return json_decode($json, true);
}
$temp = json_change_key($temp, 'player', 'golfer');
print_r($temp);
Demo
If you want multiple key replace, here is the trick,
$var = '[{"player":"Tiger Woods", "wins":"10","losses":"3"},{"player":"Gary Player","wins":"7", "losses":6}]';
$temp = json_decode($var, true);
function recursive_change_key($arr, $set)
{
if (is_array($arr) && is_array($set)) {
$newArr = [];
foreach ($arr as $k => $v) {
$key = array_key_exists($k, $set) ? $set[$k] : $k;
$newArr[$key] = is_array($v) ? recursive_change_key($v, $set) : $v;
}
return $newArr;
}
return $arr;
}
$set = [
"player" => "golfers",
"wins" => "victories",
"losses" => "defeats"
];
$temp = recursive_change_key($temp, $set);
print_r($temp);
Demo.
$a = '[{"player":"Tiger Woods"},{"player":"Gary Player"}]';
$array = json_decode($a, true);
foreach($array as $key=>$value){
if(array_keys($value)[0] === "player"){
$array[$key] = ["golfer" => array_values($value)[0]];
};
}
echo json_encode($array);
you can write the value of the key to a new key and then delete the old.
renaming a key called "a" to "b", while keeping the value.
var json = {
"a" : "one"
}
json["b"] = json["a"];
delete json["a"];
for your example, just use this with a loop.
source: https://sciter.com/forums/topic/how-to-rename-the-key-of-json/
I need compare 2 arrays , the first array have one order and can´t change , in the other array i have different values , the first array must compare his id with the id of the other array , and if the id it´s the same , take the value and replace for show all in the same order
For Example :
$array_1=array("1a-dogs","2a-cats","3a-birds","4a-people");
$array_2=array("4a-walking","2a-cats");
The Result in this case i want get it´s this :
"1a-dogs","2a-cats","3a-birds","4a-walking"
If the id in this case 4a it´s the same , that entry must be modificate and put the value of other array and stay all in the same order
I do this but no get work me :
for($fte=0;$fte<count($array_1);$fte++)
{
$exp_id_tmp=explode("-",$array_1[$fte]);
$cr_temp[]="".$exp_id_tmp[0]."";
}
for($ftt=0;$ftt<count($array_2);$ftt++)
{
$exp_id_targ=explode("-",$array_2[$ftt]);
$cr_target[]="".$exp_id_targ[0]."";
}
/// Here I tried use array_diff and others but no can get the results as i want
How i can do this for get this results ?
Maybe you could use the array_udiff_assoc() function with a callback
Here you go. It's not the cleanest code I've ever written.
Runnable example: http://3v4l.org/kUC3r
<?php
$array_1=array("1a-dogs","2a-cats","3a-birds","4a-people");
$array_2=array("4a-walking","2a-cats");
function getKeyStartingWith($array, $startVal){
foreach($array as $key => $val){
if(strpos($val, $startVal) === 0){
return $key;
}
}
return false;
}
function getMergedArray($array_1, $array_2){
$array_3 = array();
foreach($array_1 as $key => $val){
$startVal = substr($val, 0, 2);
$array_2_key = getKeyStartingWith($array_2, $startVal);
if($array_2_key !== false){
$array_3[$key] = $array_2[$array_2_key];
} else {
$array_3[$key] = $val;
}
}
return $array_3;
}
$array_1 = getMergedArray($array_1, $array_2);
print_r($array_1);
First split the 2 arrays into proper key and value pairs (key = 1a and value = dogs). Then try looping through the first array and for each of its keys check to see if it exists in the second array. If it does, replace the value from the second array in the first. And at the end your first array will contain the result you want.
Like so:
$array_1 = array("1a-dogs","2a-cats","3a-birds","4a-people");
$array_2 = array("4a-walking","2a-cats");
function splitArray ($arrayInput)
{
$arrayOutput = array();
foreach ($arrayInput as $element) {
$tempArray = explode('-', $element);
$arrayOutput[$tempArray[0]] = $tempArray[1];
}
return $arrayOutput;
}
$arraySplit1 = splitArray($array_1);
$arraySplit2 = splitArray($array_2);
foreach ($arraySplit1 as $key1 => $value1) {
if (array_key_exists($key1, $arraySplit2)) {
$arraySplit1[$key1] = $arraySplit2[$key1];
}
}
print_r($arraySplit1);
See it working here:
http://3v4l.org/2BrVI
$array_1=array("1a-dogs","2a-cats","3a-birds","4a-people");
$array_2=array("4a-walking","2a-cats");
function merge_array($arr1, $arr2) {
$arr_tmp1 = array();
foreach($arr1 as $val) {
list($key, $val) = explode('-', $val);
$arr_tmp1[$key] = $val;
}
foreach($arr2 as $val) {
list($key, $val) = explode('-', $val);
if(array_key_exists($key, $arr_tmp1))
$arr_tmp1[$key] = $val;
}
return $arr_tmp1;
}
$result = merge_array($array_1, $array_2);
echo '<pre>';
print_r($result);
echo '</pre>';
This short code works properly, you'll get this result:
Array
(
[1a] => dogs
[2a] => cats
[3a] => birds
[4a] => walking
)
I got stuck somehow on the following problem:
What I want to achieve is to merge the following arrays based on key :
{"Entities":{"submenu_id":"Parents","submenu_label":"parents"}}
{"Entities":{"submenu_id":"Insurers","submenu_label":"insurers"}}
{"Users":{"submenu_id":"New roles","submenu_label":"newrole"}}
{"Users":{"submenu_id":"User - roles","submenu_label":"user_roles"}}
{"Users":{"submenu_id":"Roles - permissions","submenu_label":"roles_permissions"}}
{"Accounting":{"submenu_id":"Input accounting data","submenu_label":"new_accounting"}}
Which needs to output like this:
[{"item_header":"Entities"},
{"list_items" :
[{"submenu_id":"Parents","submenu_label":"parents"},
{"submenu_id":"Insurers","submenu_label":"insurers"}]
}]
[{"item_header":"Users"},
{"list_items" :
[{"submenu_id":"New roles","submenu_label":"newrole"}
{"submenu_id":"User - roles","submenu_label":"user_roles"}
{"submenu_id":"Roles - permissions","submenu_label":"roles_permissions"}]
}]
[{"item_header":"Accounting"},
{"list_items" :
[{"submenu_id":"Input accounting data","submenu_label":"new_accounting"}]
}]
I have been trying all kinds of things for the last two hours, but each attempt returned a different format as the one required and thus failed miserably. Somehow, I couldn't figure it out.
Do you have a construction in mind to get this job done?
I would be very interested to hear your approach on the matter.
Thanks.
$input = array(
'{"Entities":{"submenu_id":"Parents","submenu_label":"parents"}}',
'{"Entities":{"submenu_id":"Insurers","submenu_label":"insurers"}}',
'{"Users":{"submenu_id":"New roles","submenu_label":"newrole"}}',
'{"Users":{"submenu_id":"User - roles","submenu_label":"user_roles"}}',
'{"Users":{"submenu_id":"Roles - permissions","submenu_label":"roles_permissions"}}',
'{"Accounting":{"submenu_id":"Input accounting data","submenu_label":"new_accounting"}}',
);
$input = array_map(function ($e) { return json_decode($e, true); }, $input);
$result = array();
$indexMap = array();
foreach ($input as $index => $values) {
foreach ($values as $k => $value) {
$index = isset($indexMap[$k]) ? $indexMap[$k] : $index;
if (!isset($result[$index]['item_header'])) {
$result[$index]['item_header'] = $k;
$indexMap[$k] = $index;
}
$result[$index]['list_items'][] = $value;
}
}
echo json_encode($result);
Here you are!
In this case, first I added all arrays into one array for processing.
I thought they are in same array first, but now I realize they aren't.
Just make an empty $array=[] then and then add them all in $array[]=$a1, $array[]=$a2, etc...
$array = '[{"Entities":{"submenu_id":"Parents","submenu_label":"parents"}},
{"Entities":{"submenu_id":"Insurers","submenu_label":"insurers"}},
{"Users":{"submenu_id":"New roles","submenu_label":"newrole"}},
{"Users":{"submenu_id":"User - roles","submenu_label":"user_roles"}},
{"Users":{"submenu_id":"Roles - permissions","submenu_label":"roles_permissions"}},
{"Accounting":{"submenu_id":"Input accounting data","submenu_label":"new_accounting"}}]';
$array = json_decode($array, true);
$intermediate = []; // 1st step
foreach($array as $a)
{
$keys = array_keys($a);
$key = $keys[0]; // say, "Entities" or "Users"
$intermediate[$key] []= $a[$key];
}
$result = []; // 2nd step
foreach($intermediate as $key=>$a)
{
$entry = ["item_header" => $key, "list_items" => [] ];
foreach($a as $item) $entry["list_items"] []= $item;
$result []= $entry;
}
print_r($result);
I would prefer an OO approach for that.
First an object for the list_item:
{"submenu_id":"Parents","submenu_label":"parents"}
Second an object for the item_header:
{"item_header":"Entities", "list_items" : <array of list_item> }
Last an object or an array for all:
{ "Menus: <array of item_header> }
And the according getter/setter etc.
The following code will give you the requisite array over which you can iterate to get the desired output.
$final_array = array();
foreach($array as $value) { //assuming that the original arrays are stored inside another array. You can replace the iterator over the array to an iterator over input from file
$key = /*Extract the key from the string ($value)*/
$existing_array_for_key = $final_array[$key];
if(!array_key_exists ($key , $final_array)) {
$existing_array_for_key = array();
}
$existing_array_for_key[count($existing_array_for_key)+1] = /*Extract value from the String ($value)*/
$final_array[$key] = $existing_array_for_key;
}
I have $options as an associative array with each value as mixed(can be strings, or other arrays). I won't have any objects there.
$keys is a numeric array & the number of keys is determined at runtime.
I want to have a result similar to this expression
$options[$keys[0]][$keys[1]].......[$keys[count($keys)-1]] = $value;
For example, if $keys = array('key1'), i want to do
$options['key1'] = $value;
& if $keys = array('key1', 'key2'), i want to do
$options['key1']['key2'] = $value;
& so on
The problem with array_replace_recursive is that $value may itself be an array. Someway to constrain the depth to which array_replace_recursive can go? or maybe some other way?
I made something similar like this:
$options = array('key1' => array('key2' => array('key3' => 'value')));
$keys = array('key1', 'key2', 'key3');
$search = &$options;
foreach ($keys as $key) {
$search = &$search[$key];
}
$search = 'changed value';
var_dump($options);
You could always create references to the next key.
I think this is not possible, As array is a data structure and you can not put code or loop inside it. Let me google i will update you once i get some solution :)
I finally got it working. Thanks to #Benjamin Paap. His answer helped to get to the exact solution
$options = array('key1' => array('key2' => array('key3' => 'value')));
$keys = array('key1', 'key2', 'key3');
$length = count($keys);
$search = &$options;
foreach ($keys as $key => $value) {
// key doesn't exist or value is not an array
if(!isset($search[$value]) || !is_array($search)) {
$search = (array) $search;
$search[$value] = array();
}
$search = &$search[$value];
// last iteration
if($length - 1 === $key) {
$search = 'new value';
}
}
unset($search);
var_dump($options);