I have the following array:
$array = array('23' => array('19' => array('7' => array('id' => 7, 'name' => 'John Doe'))));
Array
(
[23] => Array
(
[19] => Array
(
[7] => Array
(
[id] => 7
[name] => John Doe
)
)
)
)
I want to access sub-element and i know his sub keys that 23 19 7. I can do this with simple format
echo $array['23']['19']['7']['name']; // John Doe
But these array have just 3 level and this may vary, more or less. I have to make an array unlimited level.
I tried that like i want with following codes:
$keys = array('23', '19', '7');
echo $array[$keys]['name'];
And of course i got Warning: Illegal offset type in error.
Then i tried this one but i couldnt get any element:
function brackets($str) {
return sprintf("['%s']", $str);
}
$keys = array('23', '19', '7');
$string_key = implode('', array_map('brackets', $keys)); // ['23']['19']['7']
echo $array{$string_key}['name'];
You can make a function that you can call with a key-array.
function getArrayPathVal($arr, $path){
if(!is_array($path))
return $arr[$path];
$curr = $arr;
foreach($path as $key)
{
if(!$curr[$key])
return false;
$curr = $curr[$key];
}
return $curr;
}
$array = array('23' => array('19' => array('7' => array('id' => 7, 'name' => 'John Doe'))));
$keys = array('23', '19', '7');
$res = getArrayPathVal($array, $keys);
print $res['name']; //Prints 'John Doe'
You could try a recursive function:
function getByKeys ($arr, $keys) {
if (count($keys) == 0)
return $arr;
$key = array_shift ($keys);
return getByKeys ($arr[$key], $keys);
}
$array = array('23' => array('19' => array('7' => array('id' => 7, 'name' => 'John Doe'))));
echo getByKeys ($array, array('23', '19', '7'));
this is untested, but the concept should do the trick:
retrieve the next key to be applied to the array
next iteration using the sub-array denoted by that key
stop if no more keys should be applied.
Related
I want to come up with $desired_output from given $data array below using array_map() or any PHP array_* built-in function. Any idea how?
$data = array(
'posted_name' => 'John Doe',
'posted_age' => '30',
);
$desired_output = array(
'name' => 'John Doe',
'age' => '30',
);
I tried below but the result is an array of arrays:
$desired_output = array_map(
function($keys, $vals)
{
$new[substr($keys, strlen('posted_'))] = $vals;
return $new;
},
array_keys($data),
$data
);
print_r($desired_output );
/**
* Array (
[0] => Array ( [name] => John Doe )
[1] => Array ( [age] => 30 )
)
*/
What about the following:
$desired_output = array();
array_walk(
$data,
function(&$val, $key) use (&$desired_output)
{
$len = strlen('posted_');
if (substr($key, 0, $len) == "posted_") {
$key = substr($key, $len);
}
$desired_output[$key] = $val;
}
);
print_r($desired_output);
Changes:
Using array_walk instead of array_map since _map cannot handle keys
Creating an empty array to build the result in
Using that array in the scope of the lambda function
Replacing the "posted_" only if it exists in the key
Output:
$ php -f ~/tmp/so2.php
Array
(
[name] => John Doe
[age] => 30
)
I have 2 arrays that contain user details, including emails addresses. I would like to create a new array that contain only the user details where email that appear in both arrays. is there any function that do that?
I tried to use "array_intersect_assoc". no good...
$newGroupsArray = array_intersect ($firstArray , $secondArray );
for instance, - in this example only "nathalie" details should be in the new array.
Is there any function that do that?
$firstArray = array( 0 => Array ( 'name' => 'ronen', 'email' => 'ronen$Experts.com' , 'contactID' => 43 ) ,
1 => Array ( 'name' => 'shlomig' , 'email' => 'shlomig$tours.co.il' ,'contactID' => 28 ) ,
2 => Array ( 'name' => 'nathalie', 'email' => 'nathalie$obra.co.il', 'contactID' => 57 )
);
$secondArray = array(0 => Array ( 'name' => 'nathalie', 'email' => 'nathalie$obra.co.il', 'contactID' => 57 ) ,
1 => Array ('name' => 'roi' , 'email' => 'roi$mail.com' ,'contactID' => 99 )
);
You can combine array_values and array_intersect_key to get desired result.
$Array1 = array();
$Array2 = array();
foreach ($firstArray as $value)
{
$Array1[$value['email']] = $value;
}
foreach ($secondArray as $value)
{
$Array2[$value['email']] = $value;
}
$matches = array_values(array_intersect_key($Array1, $Array2));
print_r($matches);
You can also use foreach loops and check the data using an if condition as below.
$matches = array();
foreach($firstArray as $key => $value)
{
foreach($secondArray as $value1)
{
if($value['email'] === $value1['email'])
$matches[] = $value;
}
}
print_r($matches);
I am trying to uniformly rename all of my array keys using a foreach loop and unset.
Array before:
Array
( [0] => Array (
[store_nl] => Store One
[id_nl] => 123456
[title_nl] => Product One
[price_nl] => $9.00 )
[1] => Array (
[store_ds] => Store Two
[id_ds] => 789012
[title_ds] => Product Two
[price_ds] => $8.00 )
)
foreach using unset:
if(isset($data)){
foreach ( $data as $k=>$v )
{
//Store One (ds)
$data[$k]['Store'] = $data[$k]['store_ds'];
$data[$k]['ItemID'] = $data[$k]['id_ds'];
$data[$k]['Description'] = $data[$k]['title_ds'];
$data[$k]['Price'] = $data[$k]['price_ds'];
unset($data[$k]['store_ds']);
unset($data[$k]['id_ds']);
unset($data[$k]['title_ds']);
unset($data[$k]['price_ds']);
//Store Two (nl)
$data[$k]['Store'] = $data[$k]['store_nl'];
$data[$k]['ItemID'] = $data[$k]['id_nl'];
$data[$k]['Description'] = $data[$k]['title_nl'];
$data[$k]['Price'] = $data[$k]['price_nl'];
unset($data[$k]['store_nl']);
unset($data[$k]['id_nl']);
unset($data[$k]['title_nl']);
unset($data[$k]['price_nl']);
}
}
Array after:
Array
( [0] => Array (
[Store] => Store One
[ItemID] => 123456
[Description] => Product One
[Price] => $9.00 )
[1] => Array (
[Store] =>
[ItemID] =>
[Description] =>
[Price] => )
)
All of the array keys have been changed, but some of the data is now gone? Can someone please tell me a better way to do this without data loss?
The following will do what you deed:
$myArray = array(
array(
'store_ni' => 'Store One',
'id_ni' => 123456,
'title_ni' => 'Product One',
'price_ni' => '$9.00'
),
array(
'store_ds' => 'Store Two',
'id_ds' => 789012,
'title_ds' => 'Product Two',
'price_ds' => '$8.00'
)
);
$newKeys = array('Store', 'ItemID', 'Description', 'Price');
$result = array();
foreach($myArray as $innerArray)
{
$result[] = array_combine(
$newKeys,
array_values($innerArray)
);
}
array_combine() combines the first array you pass to it and assign it as the keys of the returned array and the second array you pass it as the values of that array.
Use array_flip() to flip between the keys and values, then it'll be easy to run over the values and "flip" the array again (back to its original state). It should be something like:
$tmp_arr = array_flip($arr);
$fixed_arr = array();
foreach($tmp_arr as $k => $v){
if($val == "store_nl"){
$fixed_arr[$k] = "Store";
}
// etc...
}
// and now flip back:
$arr = array_flip($fixed_arr);
The arrays should have the same number of elements, but I think that's the case here.
$data = [[
'store_nl' => 'Store One',
'id_nl' => 123456,
'title_nl' => 'Product One',
'price_nl' => '$9.00'
], [
'store_ds' => 'Store Two',
'id_ds' => 789012,
'title_ds' => 'Product Two',
'price_ds' => '$8.00'
]];
$keys = ['Store', 'ItemID', 'Description', 'Price'];
$data = [
'nl' => array_combine($keys, $data[0]),
'ds' => array_combine($keys, $data[1])
];
Recursive php rename keys function:
function replaceKeys($oldKey, $newKey, array $input){
$return = array();
foreach ($input as $key => $value) {
if ($key===$oldKey)
$key = $newKey;
if (is_array($value))
$value = replaceKeys( $oldKey, $newKey, $value);
$return[$key] = $value;
}
return $return;
}
This question already has answers here:
Change array key without changing order
(8 answers)
Closed 7 years ago.
How i can do this:
$array = array('a' => 1, 'd' => 2, 'c' => 3); //associative array
// rename $array['d'] as $array['b']
$array = replace_key_function($array, 'd', 'b');
var_export($array); // array('a' => 1, 'b' => 2, 'c' => 3); same order!
I didn't see a function that does that.
There is a way to do this?
http://ideone.com/nCZnY
$array = array('a' => 1, 'd' => 2, 'c' => 3); //associative array
// rename $array['d'] as $array['b']
$array = replace_key_function($array, 'd', 'b');
var_export($array); // array('a' => 1, 'b' => 2, 'c' => 3); same order!
function replace_key_function($array, $key1, $key2)
{
$keys = array_keys($array);
$index = array_search($key1, $keys);
if ($index !== false) {
$keys[$index] = $key2;
$array = array_combine($keys, $array);
}
return $array;
}
There is a flaw in the logic of the accepted answer.
If you have an array like this:
[
'k1'=>'k1',
'k2'=>'k2',
'k3',
'k4'=>'k4'
]
and replace 'k4' with 'something' you will get an output like this:
[
'k1'=>'k1',
'k2'=>'k2',
'something' => 'k3',
'k4'=>'k4'
]
Here is a quick fix that solves the problem:
function replace_key_function($array, $key1, $key2)
{
$keys = array_keys($array);
//$index = array_search($key1, $keys);
$index = false;
$i = 0;
foreach($array as $k => $v){
if($key1 === $k){
$index = $i;
break;
}
$i++;
}
if ($index !== false) {
$keys[$index] = $key2;
$array = array_combine($keys, $array);
}
return $array;
}
EDIT:2014/12/03
The accepted answer does work if you set the third parameter (strict) of array_search to true.
Instead of using loops, you could always flatten to string with json_encode(), perform a string replacement, then json_decode() back to an array:
function replaceKey($array, $old, $new)
{
//flatten the array into a JSON string
$str = json_encode($array);
// do a simple string replace.
// variables are wrapped in quotes to ensure only exact match replacements
// colon after the closing quote will ensure only keys are targeted
$str = str_replace('"'.$old.'":','"'.$new.'":',$str);
// restore JSON string to array
return json_decode($str, TRUE);
}
Now this doesn't check for conflicts with pre-existing keys (easy enough to add a string comparison check), and it might not be the best solution for single replacements in massive arrays.. but the nice part about flattening the array into a string for replacement is that it effectively makes replacement recursive since matches at any depth are all replaced in one pass:
$arr = array(
array(
'name' => 'Steve'
,'city' => 'Los Angeles'
,'state' => 'CA'
,'country' => 'USA'
,'mother' => array(
'name' => 'Jessica'
,'city' => 'San Diego'
,'state' => 'CA'
,'country' => 'USA'
)
)
,array(
'name' => 'Sara'
,'city' => 'Seattle'
,'state' => 'WA'
,'country' => 'USA'
,'father' => array(
'name' => 'Eric'
,'city' => 'Atlanta'
,'state' => 'GA'
,'country' => 'USA'
,'mother' => array(
'name' => 'Sharon'
,'city' => 'Portland'
,'state' => 'OR'
,'country' => 'USA'
)
)
)
);
$replaced = replaceKey($arr,'city','town');
print_r($replaced);
outputs
Array
(
[0] => Array
(
[name] => Steve
[town] => Los Angeles
[state] => CA
[country] => USA
[mother] => Array
(
[name] => Jessica
[town] => San Diego
[state] => CA
[country] => USA
)
)
[1] => Array
(
[name] => Sara
[town] => Seattle
[state] => WA
[country] => USA
[father] => Array
(
[name] => Eric
[town] => Atlanta
[state] => GA
[country] => USA
[mother] => Array
(
[name] => Sharon
[town] => Portland
[state] => OR
[country] => USA
)
)
)
)
A generic and simple solution with PHP 5.3+ using array_walk:
$array = array('a' => 1, 'd' => 2, 'c' => 3); //associative array
$array = replace_keys($array, array('d' => 'b'));
var_export($array); // array('a' => 1, 'b' => 2, 'c' => 3); same order!
function replace_keys(array $source, array $keyMapping) {
$target = array();
array_walk($source,
function ($v, $k, $keyMapping) use (&$target) {
$mappedKey = isset($keyMapping[$k]) ? $keyMapping[$k] : $k;
$target[$mappedKey] = $v;
},
$keyMapping);
return $target;
}
a good answer has been posted, but here's my two pence:
$array = array('a'=>1, 'd'=>2, 'c'=>3);
// rename 'd' to 'b'
foreach($array as $k=>$v){
if($k == 'd') { $k='b'; }
$newarray[$k] = $v;
}
$array = $newarray;
in response to mike-purcell would this be a more accepted approach to my example above?
changeKey($array, 'd', 'b');
function changeKey($array, $oldKey, $newKey)
{
foreach($array as $k=>$v){
if($k == $oldKey) { $k = $newKey; }
$returnArray[$k] = $v;
}
return $returnArray;
}
I'm always looking to improve :)
I have two arrays of animals (for example).
$array = array(
array(
'id' => 1,
'name' => 'Cat',
),
array(
'id' => 2,
'name' => 'Mouse',
)
);
$array2 = array(
array(
'id' => 2,
'age' => 321,
),
array(
'id' => 1,
'age' => 123,
)
);
How can I merge the two arrays into one by the ID?
#Andy
http://se.php.net/array_merge
That was my first thought but it doesn't quite work - however array_merge_recursive might work - too lazy to check right now.
This does what Erik suggested (id no. as array key) and merges vlaues in $array2 to $results.
$results = array();
foreach($array as $subarray)
{
$results[$subarray['id']] = array('name' => $subarray['name']);
}
foreach($array2 as $subarray)
{
if(array_key_exists($subarray['id'], $results))
{
// Loop through $subarray would go here if you have extra
$results[$subarray['id']]['age'] = $subarray['age'];
}
}
First off, why don't you use the ID as the index (or key, in the mapping-style array that php arrays are imo)?
$array = array(
1 => array(
'name' => 'Cat',
),
2 => array(
'name' => 'Mouse',
)
);
after that you'll have to foreach through one array, performing array_merge on the items of the other:
foreach($array2 as $key=>$value) {
if(!is_array($array[$key])) $array[$key] = $value;
else $array[$key] = array_merge($array[key], $value);
}
Something like that at least. Perhaps there's a better solution?
<?php
$a = array('a' => '1', 'b' => array('t' => '4', 'g' => array('e' => '8')));
$b = array('c' => '3', 'b' => array('0' => '4', 'g' => array('h' => '5', 'v' => '9')));
$c = array_merge_recursive($a, $b);
print_r($c);
?>
array_merge_recursive — Merge two or more arrays recursively
outputs:
Array
(
[a] => 1
[b] => Array
(
[t] => 4
[g] => Array
(
[e] => 8
[h] => 5
[v] => 9
)
[0] => 4
)
[c] => 3
)
#Andy
I've already looked at that and didn't see how it can help merge multidimensional arrays. Maybe you could give an example.
#kevin
That is probably what I will need to do as I think the code below will be very slow.
The actual code is a bit different because I'm using ADOdb (and ODBC for the other query) but I'll make it work and post my own answer.
This works, however I think it will be very slow as it goes through the second loop every time:
foreach($array as &$animal)
{
foreach($array2 as $animal2)
{
if($animal['id'] === $animal2['id'])
{
$animal = array_merge($animal, $animal2);
break;
}
}
}
foreach ($array as $a)
$new_array[$a['id']]['name'] = $a['name'];
foreach ($array2 as $a)
$new_array[$a['id']]['age'] = $a['age'];
and this is result:
[1] => Array
(
[name] => Cat
[age] => 123
)
[2] => Array
(
[name] => Mouse
[age] => 321
)
<?php
$array1 = array("color" => "red", 2, 4);
$array2 = array("a", "b", "color" => "green", "shape" => "trapezoid", 4);
$result = array_merge($array1, $array2);
print_r($result);
?>
With PHP 5.3 you can do this sort of merge with array_replace_recursive()
http://www.php.net/manual/en/function.array-replace-recursive.php
You're resultant array should look like:
Array (
[0] => Array
(
[id] => 2
[name] => Cat
[age] => 321
)
[1] => Array
(
[id] => 1
[name] => Mouse
[age] => 123
)
)
Which is what I think you wanted as a result.
I would rather prefer array_splice over array_merge because of its performance issues, my solution would be:
<?php
array_splice($array1,count($array1),0,$array2);
?>
$new = array();
foreach ($array as $arr) {
$match = false;
foreach ($array2 as $arr2) {
if ($arr['id'] == $arr2['id']) {
$match = true;
$new[] = array_merge($arr, $arr2);
break;
}
}
if ( !$match ) $new[] = $arr;
}