Add item to parent item within a multi dimensional array - php

I have a multi dimensional array, something like this:
$items = array(
'one' => array(
'a' => array(),
'b' => array(),
'c' => array()
),
'two' => array(
'd' => array(),
'e' => array(),
'f' => array()
),
'three' => array(
'g' => array(),
'h' => array(),
'i' => array()
)
);
So, I could add another array within the tree structure as:
$items['one']['c'][] = array( 'j' => array() );
But if I don't know that c is within one, how can I achieve this? I've looked at array_search but that just returns false. I think that is because what I'm looking for isn't at the top level of the array perhaps?
I know that c exists, but I don't know which sub-array it's in and how far down it goes. Is this possible?

If I understand you correctly, this function will do what you want:
<?php
$items = array(
'one' => array(
'a' => array(),
'b' => array(),
'c' => array()
),
'two' => array(
'd' => array(),
'e' => array(),
'f' => array()
),
'three' => array(
'g' => array(),
'h' => array(),
'i' => array()
)
);
function addToSub($items, $key, $addItem) {
foreach($items as &$item) {
if (in_array($key, array_keys($item))) {
$item[$key][] = $addItem;
}
}
return $items;
}
$items = addToSub($items, 'c', array( 'j' => array() ));
echo "<pre>";
var_dump($items);
echo "</pre>";
output:
array(3) {
["one"]=>
array(3) {
["a"]=>
array(0) {
}
["b"]=>
array(0) {
}
["c"]=>
array(1) {
[0]=>
array(1) {
["j"]=>
array(0) {
}
}
}
}

I think you are implementing a tree.
Your first thing to do is to find the node to append a child.
(In your example, the node is c and the child is j)
Implementing DFS search by recursion, I wrote following code.
(Make sure the node you're searching exists, or the function will return empty array)
<?php
$arr = [
'one' => [
'a' => [],
'b' => [],
'c' => [],
],
'two' => [
'd' => [],
'e' => [],
'f' => [],
],
'three' => [
'g' => [],
'h' => [],
'i' => [],
],
];
$arr = insertArr($arr, 'c', 'j');
print_r($arr);
function insertArr(array $arr, string $key, string $new): array {
// If key is found in $arr, append the child and return it.
if (array_key_exists($key, $arr)) {
$arr[$key][$new] = [];
return $arr;
}
// search the key in child node(next dimention)
foreach ($arr as $subArrKey => $subArr) {
// result will be empty if the key is not in child $subArr
$result = insertArr($subArr, $key, $new);
if (!empty($result)) {
// If the key is found in $subArr,
// replace $subArr with $result,
// which is the same as the $subArr but appended with child.
$arr[$subArrKey] = $result;
return $arr;
}
}
return [];
}
Now, you can append 'k' to either 'one', 'c' or 'j'.
To append 'k' to 'j', simply write:
$arr = insertArr($arr, 'j', 'k');

array_search will look for a value and in your example all your sub arrays are empty.
If I am not mistaken you could use array_map and for each subarray check if the key exists that you are looking for with array_key_exists:
$result = array_map(function($item) {
if (array_key_exists("c", $item)) {
$item["c"]["j"] = [];
}
return $item;
}, $items);
Demo

Related

Array slice like hash slice in perl

Is there built-in function, or shorter way to extract elements into new array, as described here?
<?php
function arr_slice ($arr, $keys) {
$ret = array();
foreach ($keys as $k) { $ret[$k] = $arr[$k]; }
return $ret;
}
$array = array(
"a" => 1,
"b" => 2,
"c" => 3,
"d" => 4,
);
var_export(
arr_slice($array, array("x","d","b"))
);
output (key order matters)
array (
'x' => NULL,
'd' => 4,
'b' => 2,
)

How to replace key in multidimensional array and maintain order

Given this array:
$list = array(
'one' => array(
'A' => 1,
'B' => 100,
'C' => 1234,
),
'two' => array(
'A' => 1,
'B' => 100,
'C' => 1234,
'three' => array(
'A' => 1,
'B' => 100,
'C' => 1234,
),
'four' => array(
'A' => 1,
'B' => 100,
'C' => 1234,
),
),
'five' => array(
'A' => 1,
'B' => 100,
'C' => 1234,
),
);
I need a function(replaceKey($array, $oldKey, $newKey)) to replace any key 'one', 'two', 'three', 'four' or 'five' with a new key independently of the depth of that key. I need the function to return a new array, with the same order and structure.
I already tried working with answers from this questions but I can't find a way to keep the order and access the second level in the array:
Changing keys using array_map on multidimensional arrays using PHP
Change array key without changing order
PHP rename array keys in multidimensional array
This is my attempt that doesn't work:
function replaceKey($array, $newKey, $oldKey){
foreach ($array as $key => $value){
if (is_array($value))
$array[$key] = replaceKey($value,$newKey,$oldKey);
else {
$array[$oldKey] = $array[$newKey];
}
}
return $array;
}
Regards
This function should replace all instances of $oldKey with $newKey.
function replaceKey($subject, $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($subject)) return $subject;
$newArray = array(); // empty array to hold copy of subject
foreach ($subject 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
$newArray[$key] = replaceKey($value, $newKey, $oldKey);
}
return $newArray;
}

How do I combine two values from the same associative array?

I have an array that I need to get a value from within the same array that is unassigned to a variable:
return ['a' => 1, 'b'=> 'a', 'c' => 2];
So in this case I need 'b' to return the same value as 'a'. Which would be 1
Thanks for the help.
edit
I intend on running a function on b's value so the value of b is slightly different than a
return ['a' => 1, 'b'=> myFunction('a'), 'c' => 2];
You can try this way.
foreach ($array as $key => $agent) {
$array[$key]['agent_address_1'] = $agent['agent_company_1'] . ', ' .$agent['agent_address_1'];
unset($array[$key]['agent_company_1']);
}
What you want is not clear.
But i am assuming that you are trying to get the 'b' element of an array to be assigned a value similar to the value of 'a' element of that same array
If that is what you need, this will do it.
<?php
$a = array('a' => 1, 'b' => null, 'c' => 2);
$a['b'] = myFunction($a, 'a');
function myFunction($a, $b)
{
return $a[$b];
}
var_dump($a);
You can then return the array, or do what you want with it.
Maybe something like
<?php
function resolve(array $arr) {
foreach($arr as &$v) {
if ( isset($arr[$v])) {
$v = $arr[$v];
}
}
return $arr;
}
function foo() {
return resolve( ['a' => '5', 'b'=>'a', 'c' => '1'] );
}
var_export( foo() );
will do, prints
array (
'a' => '5',
'b' => '5',
'c' => '1',
)
But keep in mind that resolve( ['b'=>'a', 'a' => 'c', 'c' => '1'] ); will return
array (
'b' => 'c',
'a' => '1',
'c' => '1',
)
(you could resolve that with while( isset($arr[$v])) { instead of if ( isset($arr[$v]) ) { ...but there are most likely more elegant/performant ways to do that)

PHP : Rename keys of associative array to the value of a child element when given the childs key name

Is there a PHP function I've missed that will change the keys of the parent array when given the key name of its child(associative array) or is there at least an alternative to a foreach loop which i am using at the moment to change the keys.
Example array
$arr = array(
array(
'id' => 1,
'name' => 'one',
),
array(
'id' => 2,
'name' => 'two',
),
array(
'id' => 3,
'name' => 'three',
)
);
I would like it to work like so..
$arr_name = array_change_key($arr,'name');
print_r($arr_name);
$arr_name => array(
'one', => array(
'id' => 1,
'name' => 'one',
),
'two' => array(
'id' => 2,
'name' => 'two',
),
'three' => array(
'id' => 3,
'name' => 'three',
)
);
//$arr is unchanged
This is just an added extra (not sure if possible)
array_change_key($arr,'name');
print_r($arr);
//$arr has changed because it doesn't have a variable to set
$arr => array(
'one', => array(
'id' => 1,
'name' => 'one',
),
'two' => array(
'id' => 2,
'name' => 'two',
),
'three' => array(
'id' => 3,
'name' => 'three',
)
);
print_r($arr[0]); //undefined index
If I understand the question correctly, something like:
$arr = array_combine(
array_column($arr, 'name'),
$arr
);
will use the name value from each record as the parent key, and give
array(3) {
["one"]=>
array(2) {
["id"]=>
int(1)
["name"]=>
string(3) "one"
}
["two"]=>
array(2) {
["id"]=>
int(2)
["name"]=>
string(3) "two"
}
["three"]=>
array(2) {
["id"]=>
int(3)
["name"]=>
string(5) "three"
}
}
You would have to tell the function whether or not to "pass by reference" it has no way of knowing whether you are trying to set the returned result to a variable;
function array_change_key(array &$array, $key, $pass_by_reference = false){
if($pass_by_reference){
// check is_scalar($key)
if(!is_scalar($key)) return FALSE;
// we already know isset($array), is_array($array) and isset(key) are true because $pass_by_reference is true;
$array = markBakersAnswer($array,$key);
return TRUE;
// pass-by-reference functions usually return true or false
}
return markBakersAnswer($array,$key);
}
MarkBakersAnswer +1
$new_array = array_change_key($arr, 'name'); // $arr unchanged and $new_array == array with new keys
$new_array = array_change_key($arr, 'name', false); // $arr unchanged and $new_array == array with new keys
$new_array = array_change_key($arr, 'name', true); // $arr changed (new keys), $new_array = TRUE;
$new_array = array_change_key($arr, array(), true); // $arr changed (new keys), $new_array = FALSE;

Compare values from three arrays PHP?

I have a maybe stupid question?
I have three arrays. And I want to get different values from the first and third array. I created the following code but the returned values are wrong.
function ec($str){
echo $str.'<br>';
}
$arr1 = array( array(
'letter' => 'A',
'number' => '1'
),
array(
'letter' => 'B',
'number' => '2'
),
array(
'letter' => 'C',
'number' => '3'
)
);
$arr2 = array( array(
'letter' => 'A',
'number' => '1'
),
array(
'letter' => 'B',
'number' => '2'
)
);
$arr3 = array( array(
'letter' => 'D',
'number' => '4'
),
array(
'letter' => 'E',
'number' => '5'
)
);
$mergeArr = array_merge($arr1,$arr3);
foreach ($mergeArr as $kMerge => $vMerge){
foreach ($arr2 as $val2){
if($val2['letter'] != $mergeArr[$kMerge]['letter']){
ec($mergeArr[$kMerge]['letter']);
}
}
}
The result of this code is:
A
B
C
C
D
D
E
E
The result I want:
C
D
E
Thanks in advance.
Based on the result you are looking for, this should do it:
$mergeArr = array_merge($arr1,$arr3);
$res = array_diff_assoc($mergeArr, $arr2);
var_dump($res);
See the snippet on codepad.
Try this instead of your foreach's:
$diff = array_diff($mergeArr, $arr2);
foreach( $diff as $d_k => $d_v ) {
ec($d_v['letter']);
}
If I understand what you are trying to do correctly, this function should do the job:
function find_unique_entries () {
$found = $repeated = array();
$args = func_get_args();
$key = array_shift($args);
foreach ($args as $arg) {
if (!is_array($arg)) return FALSE; // all arguments muct be arrays
foreach ($arg as $inner) {
if (!isset($inner[$key])) continue;
if (!in_array($inner[$key], $found)) {
$found[] = $inner[$key];
} else {
$repeated[] = $inner[$key];
}
}
}
return array_diff($found, $repeated);
}
Pass the key you are searching to the first arguments, then as many arrays as you like in the subsequent arguments. Returns an array of results or FALSE on error.
So your usage line would be:
$result = find_unique_entries('letter', $arr1, $arr2, $arr3);
See it working

Categories