I have array:
$arr = array(
'a' => 1,
'b' => 2,
'c' => 3
);
Is there built-in php function which gets array value by key and then removes element from this array?
I know array_shift and array_pop functions, but I need to get element by custom key, not first/last element. Something like:
$arr; // 'a'=>1, 'b'=>2, 'c'=>3
$elem = array_shift_key($arr, 'b');
echo $elem; // 2
$arr; // 'a'=>1, 'c'=>3
Not sure about native way, but this should work:
function shiftByKey($key, &$array) {
if (!array_key_exists($key, $array)) {
return false;
}
$tmp = $array[$key];
unset($array[$key]);
return $tmp;
}
Edit: Updated it so that array is passed by reference. Else your array stays the same.
As far as I'm aware there's nothing that comes close to that. Can be written easily though:
function array_shift_key(array &$array, $key) {
$value = $array[$key];
unset($array[$key]);
return $value;
}
If you care, validate first whether the key exists in the array and do something according to your error handling philosophy if it doesn't. Otherwise you'll simply get a standard PHP notice for non-existing keys.
function array_shift_key(array &$input, $key) {
$value = null;
// Probably key presents with null value
if (isset($input[$key]) || array_key_exists($key, $input)) {
$value = $input[$key];
unset($input[$key]);
}
return $value;
}
Related
I'm trying to update values in a multi-dimensional array (using a function so it can be done dynamically), but my approach of looping through each values doesn't seem to work. I tried different solutions offered on stackoverflow but I still can't seem to make it work as a function (with dynamic keys). Here is a simple example with a 2 level array, but it should work on any level.
function updateArrayValue($array,$key_to_find,$new_value){
foreach($array as $key => $value){
if($key == $key_to_find){
$value = $new_value;
break; // Stop the loop
}
}
return $array;
}
$array = array("001"=>"red", "002"=>"green", "003"=>array("003-001"=>"blue", "003-002"=>"yellow"));
$array = updateArrayValue($array,"003-001","purple");
var_dump($array);
You need recursion call of function and set new values. Not value only but changed deep array.
function updateArrayValue($array,$key_to_find,$new_value){
foreach($array as $key => $value){
// if value is not an array then try set new value if is search key
if(!is_array($value)){
if($key == $key_to_find) {
$array[$key] = $new_value;
}
}
else {
// otherwise call function again on value array
$array[$key] = updateArrayValue($value, $key_to_find, $new_value);
}
}
return $array;
}
$array = array(
"001"=> "red",
"002"=> "green",
"003"=> array(
"003-001"=> "blue",
"003-002"=> "yellow"
));
$newArray = updateArrayValue($array,"003-001","purple");
var_dump($newArray);
Each string value within my $arr array contains 2 preceeding white spaces. I would like to remove these spaces using the trim() method. Furthermore, I would like to do the same for any arrays within the $arr array assuming an infinite number of arrays within arrays. I attempted to do this recursively with no success.
Although there might be a built in php method to do this for me, I am learning, and would like to know why this code block doesn't work as well as what altercation can be made to fix it.
$arr = array(" one", " two", array(" three"));
function trimAll(&$array) {
foreach($array as $key => $value) {
if(gettype($value) !== "array") {
$array[$key] = trim($value);
} else {
trimAll($value);
}
}
}
trimAll($arr);
echo $arr[0];//"one" (worked)
echo $arr[1];//"two" (worked)
echo $arr[2][0];// " three"(didn't work)
The best/simplest function to call in this case is: array_walk_recursive(). There is no need to reinvent a function that php has already designed for just this purpose. It only visits "leaf nodes" so you don't need to check if it is processing an array-type element.
You merely need to modify the elements by reference (using & in the anonymous function parameter). I'll demo ltrim() since your input strings only have leading spaces, but you can use trim() to handle spaces on both sides of the string.
Code: (Demo) (PHP7.4 and higher version)
array_walk_recursive(
$arr,
function(&$v) {
$v = ltrim($v);
}
);
Output:
array (
0 => 'one',
1 => 'two',
2 =>
array (
0 => 'three',
),
)
As for your custom function, it could be written like this to provide a successful result:
function trimAll(&$array) { // modify the original input array by reference
foreach ($array as &$value) { // modify each value by reference
if (!is_array($value)) { // if it is not an array
$value = trim($value); // trim the string
} else {
trimAll($value); // recurse
}
}
}
trimAll($arr); // modify the array (no return value from function call)
var_export($arr); // print the array
You see, the reason your subarray element is not being affected is because there is no assignment occuring between $value and trimAll($value). The way you have set up trimAll, it does not return a value. So, even if you used:
} else {
$array[$key] = trimAll($value);
}
You would find that $array[$key] would be replaced by NULL. The solution is to make $value modifiable by reference by using &$value in the foreach loop.
And as if this answer wasn't long enough already, here is a way to reconfigure your function so that it returns the modified array instead of modifying the input array with no return.
function trimAll($array){ // input array is not modifiable
foreach ($array as &$value) { // $value IS modifiable
if (is_array($value)) { // if an array...
$value = trimAll($value); // assign recursion result to $value
} else { // not an array...
$value = trim($value); // trim the string
}
}
return $array; // return the new trimmed array
}
var_export(trimAll($arr)); // now trimAll() can be directly printed to screen
or if you wish to avoid modifying by reference entirely:
function trimAll($array) {
foreach ($array as $key => $value) {
if (is_array($value)) {
$array[$key] = trimAll($value);
} else {
$array[$key] = trim($value);
}
}
return $array;
}
var_export(trimAll($arr));
Yes, there is a built-in PHP function which solves your problem. It is array_map()
But in your situation, you might need to do something like this:
Solution 1:
$input = array(" one", " two", array(" three"));
function removeSpaces($object)
{
if (is_array($object)) {
$object = array_map('trim', $object);
} else {
$object = trim($object);
}
return $object;
}
$output = array_map('removeSpaces', $input);
Solution 2:
$input = array(" one", " two", array(" three"));
function array_map_recursive(callable $func, array $array) {
return filter_var($array, \FILTER_CALLBACK, ['options' => $func]);
}
$output = array_map_recursive('trim', $input);
Cheers.
Simple method,
$arr = array(" one", " two", array(" three"));
function trimAll(&$array) {
foreach($array as $key => $value) {
if(gettype($value) !== "array") {
$array[$key] = trim($value);
} else {
$array[$key] = trimAll($value);
}
}
return $array;
}
trimAll($arr);
I have a :
$value = "val";
I also have an array :
$keys = ['key1', 'key2', 'key3'...]
The keys in that array are dynamically generated, and can go from 2 to 10 or more entries.
My goal is getting this :
$array['key1']['key2']['key3']... = $value;
How can I do that ?
Thanks
The easiest, and least messy way (ie not using references) would be to use a recursive function:
function addArrayLevels(array $keys, array $target)
{
if ($keys) {
$key = array_shift($keys);
$target[$key] = addArrayLevels($keys, []);
}
return $target;
}
//usage
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, []);
It works as you can see here.
How it works is really quite simple:
if ($keys) {: if there's a key left to be added
$key = array_shift($keys); shift the first element from the array
$target[$key] = addArrayLevels($keys, []);: add the index to $target, and call the same function again with $keys (after having removed the first value). These recursive calls will go on until $keys is empty, and the function simply returns an empty array
The downsides:
Recursion can be tricky to get your head round at first, especially in complex functions, in code you didn't write, but document it well and you should be fine
The pro's:
It's more flexible (you can use $target as a sort of default/final assignment variable, with little effort (will add example below if I find the time)
No reference mess and risks to deal with
Example using adaptation of the function above to assign value at "lowest" level:
function addArrayLevels(array $keys, $value)
{
$return = [];
$key = array_shift($keys);
if ($keys) {
$return[$key] = addArrayLevels($keys, $value);
} else {
$return[$key] = $value;
}
return $return;
}
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, 'innerValue');
var_dump($subArrays);
Demo
I don't think that there is built-in function for that but you can do that with simple foreach and references.
$newArray = [];
$keys = ['key1', 'key2', 'key3'];
$reference =& $newArray;
foreach ($keys as $key) {
$reference[$key] = [];
$reference =& $reference[$key];
}
unset($reference);
var_dump($newArray);
I have a key stored in a variable like so:
$key = 4;
I tried to get the relevant value like so:
$value = $array[$key];
but it failed. Help.
Your code seems to be fine, make sure that key you specify really exists in the array or such key has a value in your array eg:
$array = array(4 => 'Hello There');
print_r(array_keys($array));
// or better
print_r($array);
Output:
Array
(
[0] => 4
)
Now:
$key = 4;
$value = $array[$key];
print $value;
Output:
Hello There
$value = ( array_key_exists($key, $array) && !empty($array[$key]) )
? $array[$key]
: 'non-existant or empty value key';
As others stated, it's likely failing because the requested key doesn't exist in the array. I have a helper function here that takes the array, the suspected key, as well as a default return in the event the key does not exist.
protected function _getArrayValue($array, $key, $default = null)
{
if (isset($array[$key])) return $array[$key];
return $default;
}
hope it helps.
It should work the way you intended.
$array = array('value-0', 'value-1', 'value-2', 'value-3', 'value-4', 'value-5' /* … */);
$key = 4;
$value = $array[$key];
echo $value; // value-4
But maybe there is no element with the key 4. If you want to get the fiveth item no matter what key it has, you can use array_slice:
$value = array_slice($array, 4, 1);
I have a unique case where I have an array like so:
$a = array('a' => array('b' => array('c' => 'woohoo!')));
I want to access values of the array in a manner like this:
some_function($a, array('a')) which would return the array for position a
some_function($a, array('a', 'b', 'c')) which would return the word 'woohoo'
So basically, it drills down in the array using the passed in variables in the second param and checks for the existence of that key in the result. Any ideas on some native php functions that can help do this? I'm assuming it'll need to make use of recursion. Any thoughts would be really appreciated.
Thanks.
This is untested but you shouldn't need recursion to handle this case:
function getValueByKey($array, $key) {
foreach ($key as $val) {
if (!empty($array[$val])) {
$array = $array[$val];
} else return false;
}
return $array;
}
You could try with RecursiveArrayIterator
Here is an example on how to use it.
Here’s a recursive implementation:
function some_function($array, $path) {
if (!count($path)) {
return;
}
$key = array_shift($path);
if (!array_key_exists($key, $array)) {
return;
}
if (count($path) > 1) {
return some_function($array[$key], $path);
} else {
return $array[$key];
}
}
And an iterative implementation:
function some_function($array, $path) {
if (!count($path)) {
return;
}
$tmp = &$array;
foreach ($path as $key) {
if (!array_key_exists($key, $tmp)) {
return;
}
$tmp = &$tmp[$key];
}
return $tmp;
}
These functions will return null if the path is not valid.
$a['a'] returns the array at position a.
$a['a']['b']['c'] returns woohoo.
Won't this do?