How to find the value of a multidimensional array by key - php

How I can search array key from multidimensional array and return found key value with parent array key if it's exist. For example I've custom array:
$array = [
'type' => 'vacancy',
'needs' => ['root' => 'active'],
'market' => 'shopping',
'red' => 'color',
'education' => 'learning',
'fruits' => [
'red' => 'apple',
'cool' => 'cherry'
]
];
For example I need search key red from current array. As you see in this array exist 2 items with key red. If array have similar keys then function return example array as response:
[
0 => ['red' => 'color'],
1 => ['red' => 'apple']
]
If search key (example type) is only once inside array then response will be like this:
['type' => 'vacancy']
I tired:
function searchKey($key, $array) {
foreach ($array as $k => $v) {
if($key === $k) {
return [$k => $v];
} elseif(is_array($v)) {
return searchKey($key, $v);
} elseif(is_array($k)) {
return searchKey($key, $k);
}
}
return false;
}
When I search key root from array result is correct but when I searching key red return false. How can be solved my function or has any performance methods for searching key and get result for my needs?

You can try this :
function findByKey($findKey, $array, $result = []) {
foreach ($array as $key => $value) {
if ($key === $findKey) {
$result[] = [$key => $value];
}
if (is_array($value)) {
$result = findByKey($findKey, $value, $result);
}
}
return $result;
}
The idea is to use a recursive function :
you loop through your array
for each key => value, you check if the key is what you want : if yes, add it to the result array, else go next
if the value is an other array, you search inside this array if you have the key you want
Now use it :
$array = [
'type' => 'vacancy',
'needs' => ['root' => 'active'],
'market' => 'shopping',
'red' => 'color',
'education' => 'learning',
'fruits' => [
'red' => 'apple',
'cool' => 'cherry'
]
];
With key type :
$result = findByKey('type', $array);
var_dump($result);
Output is :
array(1) {
[0]=>
array(1) {
["type"]=>
string(7) "vacancy"
}
}
With key red :
$result = findByKey('red', $array);
var_dump($result);
Output is :
array(2) {
[0]=>
array(1) {
["red"]=>
string(5) "color"
}
[1]=>
array(1) {
["red"]=>
string(5) "apple"
}
}
Here is a link to test it : link

Related

Filter array by keys and populate new multi-dimensional array from mutated keys and original values

I need to extract data from elements with keys that start with foo. from the below array:
[
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => '',
]
After identifying qualifying keys, I need to create a new indexed array of associative rows using the date substring from the original keys like so:
[
['date' => '2021-02-01', 'value' => '50000.00'],
['date' => '2021-03-01', 'value' => '50000.00'],
['date' => '2021-04-01', 'value' => '50000.00'],
['date' => '2021-05-01', 'value' => ''],
]
I've been able to extract the keys like so:
$keys = array_keys($theData[0]);
foreach ( $keys as $key ) {
if ( preg_match( '/foo.*/', $key ) ) {
$line = explode('.', $key);
$item[]['name'] = $line[1];
}
}
but I'm losing the values.
I then tried looping through the array manually and rebuilding the desired outcome, but the keys will change so I don't know how future-proof that would be.
Is there a wildcard approach I can take to achieve this?
You almost had it:
<?php
$theData = [
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => ''
];
$item = [];
// No need for array_keys(), foreach() can already do this
foreach( $theData as $key => $value )
{
// check if the key starts with foo.
// Regular expressions are heavy; if you'd like then substitute with:
// if ( substr( $key, 0, 4 ) === 'foo.' )
if ( preg_match( '/^foo\\./', $key ) )
{
// foo. is 4 chars long so substring from the fourth index till the end
$item[] = [
'date' => substr( $key, 4 ),
'value' => $value
];
}
}
var_dump( $item );
Output:
array(4) {
[0]=>
array(2) {
["date"]=>
string(10) "2021-02-01"
["value"]=>
string(8) "50000.00"
}
[1]=>
array(2) {
["date"]=>
string(10) "2021-03-01"
["value"]=>
string(8) "50000.00"
}
[2]=>
array(2) {
["date"]=>
string(10) "2021-04-01"
["value"]=>
string(8) "50000.00"
}
[3]=>
array(2) {
["date"]=>
string(10) "2021-05-01"
["value"]=>
string(0) ""
}
}
A simple loop, checking for the key starting with foo. and then a little code to replace foo. in the key with nothing will do the trick
If you have PHP8 or >
$arr = [
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => ''
];
$new = [];
foreach ($arr as $k => $v){
if ( str_starts_with( $k , 'foo.' ) ) {
$new[] = ['date' => str_replace('foo.', '', $k), 'value' => $v];
}
}
print_r($new);
RESULT
Array
(
[0] => Array
([date] => 2021-02-01, [value] => 50000.00)
[1] => Array
([date] => 2021-03-01, [value] => 50000.00)
[2] => Array
([date] => 2021-04-01, [value] => 50000.00)
[3] => Array
([date] => 2021-05-01, [value] => )
)
Alternatively, for PHP versions prior to PHP8
$new = [];
foreach ($arr as $k => $v){
if ( strpos( $k , 'foo.') !== FALSE && strpos( $k , 'foo.') == 0 ) {
$new[] = ['date' => str_replace('foo.', '', $k), 'value' => $v];
}
}
Using str_starts_with and explode
$arr = [];
foreach ($theData as $k => $v){
if (str_starts_with($k, "foo."))
$arr[] = ["date" => explode(".", $k)[1], "value" => $v];
}
var_dump($arr);
sscanf() is an ideal function to call which will both check for qualifying strings and extract the desired trailing date value. It doesn't use regex, but it does require a placeholder %s to target the date substring. If a given string doesn't qualify, no element is pushed into the result array.
Code: (Demo) (without compact())
$result = [];
foreach ($array as $key => $value) {
if (sscanf($key, 'foo.%s', $date)) {
// $result[] = ['date' => $date, 'value' => $value];
$result[] = compact(['date', 'value']);
}
}
var_export($result);
If you remove the optional technique of using compact(), this solution makes fewer function calls than all other answers on this page.
I would probably only use regex if I wanted to strengthen the validation for qualifying key strings. (Demo)
$result = [];
foreach ($array as $key => $value) {
if (preg_match('~^foo\.\K\d{4}-\d{2}-\d{2}$~', $key, $m)) {
$result[] = ['date' => $m[0], 'value' => $value];
}
}
var_export($result);

How to make function which return name of key associated with the array in which need to find the value?

I am trying to make a function that can be used to get the name of the key associated with the array in which need to find the value. Currently, the function does not return the name of the array key with the required value. Who could can give a solve for get need result?
$Arr = array(
"A" => array(
"A1" => array("val"=>001),
"B1" => array("val"=>002),
),
"B" => array(
"A2" => array("val"=>007)
),
);
function returnTreeWithNamesArrayToSearch_value($array, $search_value) {
foreach($array as $k => $v) {
if ($v==$search_value) return $k;
if(is_array($v)) {
$tree[]=$k;
$find = returnTreeWithNamesArrayToSearch_value($v, $search_value);
if($find) return $tree;
}
}
return null;
}
var_dump(returnTreeWithNamesArrayToSearch_value($Arr, 007));
Result:
0 => string 'A' (length=19)
1 => string 'B' (length=5)
---------------------------------------
Need result:
0 => string 'A' (length=19)
1 => string 'B' (length=5)
2 => string 'A2' (length=5)
I think the main problem is adding back in the various levels of keys, to get round this, I always return an array (just the single item is now [$k], and use array_merge() to add this output back into the list of keys.
The nearest I can get with your current structure is...
function returnTreeWithNamesArrayToSearch_value($array, $search_value){
$tree = [];
foreach($array as $k => $v){
if($v==$search_value)
return [$k];
if(is_array($v)){
$find = returnTreeWithNamesArrayToSearch_value($v, $search_value);
if($find) {
return array_merge([$k], $find);
}
}
}
return null;
}
which gives...
array(3) {
[0] =>
string(1) "B"
[1] =>
string(2) "A2"
[2] =>
string(3) "val"
}

PHP: Make an array clear?

I have an array like this:
array(
[cat] => news,
[comments_count] => 2,
[meta] => array(
[first_meta] => 44,
[second_meta] => 54,
)
)
The above code is an example of array that I have. Now I wanna make the above array clear like this:
array(
[cat] => news,
[comments_count] => 2,
[first_meta] => 44,
[second_meta] => 54,
)
(means Delete -meta- but not it's indexes. I want to add indexes of meta to the first array)
Add the meta array to the array and then unset the meta array:
$array = $array + $array['meta'];
unset($array['meta']);
You may use the below function if you have a multidimentional array and you can reuse it anywhere.
function array_flatten($array) {
if (!is_array($array)) {
return false;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, array_flatten($value));
} else {
$result[$key] = $value;
}
}
return $result;
}
$array = array(
'cat' => 'news',
'comments_count' => '2',
'meta' => array(
'first_meta' => '44',
'second_meta' => '54',
)
);
var_dump(array_flatten($array));
The result will be
array(4) {
["cat"]=>
string(4) "news"
["comments_count"]=>
string(1) "2"
["first_meta"]=>
string(2) "44"
["second_meta"]=>
string(2) "54"
}
Otherwise if you just need to flatten meta array as in your question. array_merge() the meta array and unset meta it as below.
$result = array_merge($array, $array["meta"]);
unset($result["meta"]);
var_dump($result);

Combine two arrays with just matching override

I have two arrays:
The original:
array(2) {
'app_name' =>
string(15) "dropcat-default"
'site' =>
array(1) {
'environment' =>
array(7) {
'drush_alias' =>
NULL
'backup_path' =>
string(6) "backup"
'config_name' =>
NULL
'original_path' =>
string(33) "/var/www/webroot/shared/some_path"
'symlink' =>
string(43) "/var/www/webroot/mysite_latest/symlink_path"
'url' =>
string(17) "http://localhost"
'name' =>
string(11) "mystagesite"
}
}
}
And the one with overrides:
array(2) {
'app_name' =>
string(17) "dropcat-overrides"
'site' =>
array(1) {
'environment' =>
array(1) {
'drush_alias' =>
string(6) "foobar"
}
}
}
I want to replace the overrides in the original array, but keep the keys that are not present in the override - using array_replace just writes over the existing ones, because I have arrays in arrays. Is there a simple way to solve this?
function _merge_array_rec($arr, $arr2, $i = 0)
{
foreach ($arr2 as $key => $value)
{
if (!isset($arr[$key]))
{
$arr[$key] = $value;
}
else
{
if (is_array($value))
{
$arr[$key] = _merge_array_rec($arr[$key], $arr2[$key], $i + 1);
}
else
{
$arr[$key] = $value;
}
}
}
return $arr;
}
$merge_array = _merge_array_rec($array1, $array2);
array_replace_recursive gets it done for multi dimensional arrays.
As for single dimension arrays, looping through the original array then checking if the overriding array has this value is fun enough.
Something similar to this :
$original=array();
$overriding=array();
foreach($original as $key => $value){
if(isset($overriding[$key]) && !empty($overriding[$key])){
$original[$key]=$overriding[$key];
}
}
Hope this helps
array_key_exists should be used instead of isset, because isset ignores NULL.
The structure of $overrides should be validated, shouldn't it?
Try it out.
<?php
function array_replace_recursive_if_valid(array $defaults, array $overrides) {
foreach ($overrides as $key => $value) {
if (!array_key_exists($key, $defaults)) {
continue;
}
if (is_array($defaults[$key]) && is_array($value)) {
$defaults[$key] = array_replace_recursive_if_valid($defaults[$key], $value);
continue;
}
if (!is_array($defaults[$key]) && !is_array($value)) {
$defaults[$key] = $value;
continue;
}
}
return $defaults;
}
$defaults = [
'app_name' => 'dropcat-default',
'site' => [
'environment' => [
'drush_alias' => null,
'back_path' => 'packup',
'config_name' => null,
'original_path' => '/var/www/webroot/shared/some_path',
'symlink' => '/var/www/webroot/mysite_latest/symlink_path',
'url' => 'http://localhost',
'name' => 'mystagesite',
],
],
];
$overrides = [
'app_name' => 'dropcat-overrides',
'this is invalid' => 'foo',
'site' => [
'environment' => [
'drush_alias' => 'foobar',
'url' => ['this is invalid'],
],
],
];
var_export(array_replace_recursive_if_valid($defaults, $overrides));
In the end, I ended up doing it like this:
$configs = array_replace_recursive($default_config, $env_config);
It covered my use case.

how to delete a key in array and rebuild the array in php

I got the following array
array(3) {
[0] =>
array(1) {
'Investment' =>
array(15) {
'id' =>
string(36) "53d64bec-031c-4732-b2e0-755799154b1b" ...
I would like to remove the Investment key and do the new array should be
array(3) {
[0] =>
array(15) {
'id' =>
string(36) "53d64bec-031c-4732-b2e0-755799154b1b" ...
how do I do it?
I would pass the array to array_map as such:
$array = [
[ 'Investment' => [ 'id' => '13d64bec-031c-4732-b2e0-755799154b1b' ] ],
[ 'Investment' => [ 'id' => '23d64bec-031c-4732-b2e0-755799154b1b' ] ],
[ 'Investment' => [ 'id' => '33d64bec-031c-4732-b2e0-755799154b1b' ] ],
[ 'Investment' => [ 'id' => '43d64bec-031c-4732-b2e0-755799154b1b' ] ]
];
$mappedArray = array_map(function($val) {
return $val['Investment'];
}, $array);
You can use array_map() and return the value of the 'Investment' key for each item.
$newArray = array_map(function($item) {
return $item['Investment'];
}, $oldArray);
If you do not want to copy the array, you can possibly try to use array_walk().
Edit: solution using array_walk()
array_walk($oldArray, function(&$item) {
$item = $item['Investment'];
});
store investment array in temp variable and unset as similar as given below
$tempArr = // 0 index of your array
foreach($tempArr as $key=>$val){
if(!empty($val['Investment'])){
$temp = $val['Investment'];
unset($val['Investment']);
$val[] = $temp;
}
}

Categories