Okay, so I need to dynamically dig into a JSON structure with PHP and I don't even know if it is possible.
So, let's say that my JSON is stored ad the variable $data:
$data = {
'actions':{
'bla': 'value_actionBla',
'blo': 'value_actionBlo',
}
}
So, to access the value of value_actionsBla, I just do $data['actions']['bla']. Simple enough.
My JSON is dynamically generated, and the next time, it is like this:
$data = {
'actions':{
'bla': 'value_actionBla',
'blo': 'value_actionBlo',
'bli':{
'new': 'value_new'
}
}
}
Once again, to get the new_value, I do: $data['actions']['bli']['new'].
I guess you see the issue.
If I need to dig two levels, then I need to write $data['first_level']['second_level'], with three, it will be $data['first_level']['second_level']['third_level'] and so on ...
Is there any way to perform such actions dynamically? (given I know the keys)
EDIT_0: Here is an example of how I do it so far (in a not dynamic way, with 2 levels)
// For example, assert that 'value_actionsBla' == $data['actions']['bla']
foreach($data as $expected => $value) {
$this->assertEquals($expected, $data[$value[0]][$value[1]]);
}
EDIT_1
I have made a recursive function to do it, based on the solution of #Matei Mihai:
private function _isValueWhereItSupposedToBe($supposedPlace, $value, $data){
foreach ($supposedPlace as $index => $item) {
if(($data = $data[$item]) == $value)
return true;
if(is_array($item))
$this->_isValueWhereItSupposedToBe($item, $value, $data);
}
return false;
}
public function testValue(){
$searched = 'Found';
$data = array(
'actions' => array(
'abort' => '/abort',
'next' => '/next'
),
'form' => array(
'title' => 'Found'
)
);
$this->assertTrue($this->_isValueWhereItSupposedToBe(array('form', 'title'), $searched, $data));
}
You can use a recursive function:
function array_search_by_key_recursive($needle, $haystack)
{
foreach ($haystack as $key => $value) {
if ($key === $needle) {
return $value;
}
if (is_array($value) && ($result = array_search_by_key_recursive($needle, $value)) !== false) {
return $result;
}
}
return false;
}
$arr = ['test' => 'test', 'test1' => ['test2' => 'test2']];
var_dump(array_search_by_key_recursive('test2', $arr));
The result is string(5) "test2"
You could use a function like this to traverse down an array recursively (given you know all the keys for the value you want to access!):
function array_get_nested_value($data, array $keys) {
if (empty($keys)) {
return $data;
}
$current = array_shift($keys);
if (!is_array($data) || !isset($data[$current])) {
// key does not exist or $data does not contain an array
// you could also throw an exception here
return null;
}
return array_get_nested_value($data[$current], $keys);
}
Use it like this:
$array = [
'test1' => [
'foo' => [
'hello' => 123
]
],
'test2' => 'bar'
];
array_get_nested_value($array, ['test1', 'foo', 'hello']); // will return 123
Related
I have an array that I want to search for a particular value, and then return the key. However, it's likely that there will be multiple matching values. What is the best way to return the key from the first matching value?
$agent_titles = array(
'agent_1' => sales,
'agent_2' => manager, // The key I want to return
'agent_3' => manager,
'agent_4' => director;
);
if (false !== $key = array_search('manager', $agent_titles)) {
return $key;
} else {
return;
}
In this scenario I would want to return 'agent_2'. Thanks in advance!
usage of array_search was best solution
but try write your code simple as possible
$agent_titles=[
'agent_1'=>'sales',
'agent_2'=>'manager',
'agent_3'=>'manager',
'agent_4'=>'director',
];
return array_search('manager',$agent_titles);
public function blahblah($search_value = 'manager') {
$agent_titles = [
'agent_1' => sales,
'agent_2' => manager,
'agent_3' => manager,
'agent_4' => director,
];
foreach($array as $key => $value){
if($value == $search_value){
return $key;
}
}
return false;
}
function getKeyByValue($input, $array) {
foreach ( $array as $key => $value ) {
if ( $input == $value ) {
return $key;
}
}
}
$agent_titles = array(
'agent_1' => 'sales',
'agent_2' => 'manager',
'agent_3' => 'manager',
'agent_4' => 'director'
);
var_dump(getKeyByValue('manager', $agent_titles));
I need a simple and elegant solution to check if a key has an empty value in a multidimensional array. Should return true/false.
Like this, but for a multidimensional array:
if (empty($multi_array["key_inside_multi_array"])) {
// Do something if the key was empty
}
All the questions I have found are searching for a specific value inside the multi-array, not simply checking if the key is empty and returning a true/false.
Here is an example:
$my_multi_array = array(
0 => array(
"country" => "",
"price" => 4,
"discount-price" => 0,
),
);
This will return true:
$my_key = "country";
if (check_multi_array_for_empty_value($my_multi_array, $my_key)) {
//Run this code here because the "country" key in my multi dimensional array is empty
}
This will also return true:
$my_key = "discount-price";
if (check_multi_array_for_empty_value($my_multi_array, $my_key)) {
//Run this code here because the "discount-price" key in my multi dimensional array is empty
}
This will return false:
$my_key = "price";
if (check_multi_array_for_empty_value($my_multi_array, $my_key)) {
//This WILL NOT RUN because the "price" key in my multi dimensional array is NOT empty
}
When I say empty, I mean like this empty()
UPDATE:
I am trying to adapt the code from this question but so far without any luck. Here is what I have so far, any help fixing would be appreciated:
function bg_empty_value_check($array, $key)
{
foreach ($array as $item)
{
if (is_array($item) && bg_empty_value_check($item, $key)) return true;
if (empty($item[$key])) return true;
}
return false;
}
You have to call recursive function for example i have multi dimension array
function checkMultiArrayValue($array) {
global $test;
foreach ($array as $key => $item) {
if(!empty($item) && is_array($item)) {
checkMultiArrayValue($item);
}else {
if($item)
$test[$item] = false;
else
$test[$item] = true;
}
}
return $test;
}
$multiArray = array(
0 => array(
"country" => "",
"price" => 4,
"discount-price" => 0,
),);
$test = checkMultiArrayValue($multiArray);
echo "<pre>"
print_r($test);
Will return array with true and false, who have key and index will contain true and who have index but not value contain false, you can use this array where you check your condition
Below function may help you to check empty value in nested array.
function boolCheckEmpty($array = [], $key = null)
{
if (array_key_exists($key, $array) && !empty($array[$key])) {
return true;
}
if (is_array($array)) {
foreach ((array)$array as $arrKey => $arrValue) {
if (is_array($arrValue)) {
return boolCheckEmpty($arrValue, $key);
}
if ($arrKey == $key && !empty($arrValue)) {
return $arrValue;
}
}
}
return false;
}
Usage :
$my_multi_array = array(
0 => array(
"country" => "aa",
"price" => 1,
"discount-price" => 0,
),
);
// Call
$checkEmpty = $this->boolCheckEmpty($my_multi_array, 'price');
var_dump($checkEmpty);
Note : This function also return false if value is 0 because used of empty
The following PHP function finds the node in the multi-dimensional array by matching its key:
<?php
function & findByKey($array, $key) {
foreach ($array as $k => $v) {
if(strcasecmp($k, $key) === 0) {
return $array[$k];
} elseif(is_array($v) && ($find = findByKey($array[$k], $key))) {
return $find;
}
}
return null;
}
$array = [
'key1' => [
'key2' => [
'key3' => [
'key5' => 1
],
'key4' => '2'
]
]
];
$result = findByKey($array, 'key3');
I want the function to return a reference to the node so that if I change $result then the original $array also changes (like Javascript objects).
<?php
array_splice($result, 0, 0, '2');
//Changes $array also since the `$result` is a reference to:
$array['key1']['key2']['key3']
How can I do this?
You need to do two things:
1) specify your $array parameter as a reference:
function & findByKey(&$array, $key) {
2) assign the variable $result by reference using the &:
$result = &findByKey($array, 'key3');
Since you are calling your function recursively, you need to also assign $find by reference as well.
altogether:
function & findByKey(&$array, $key) {
foreach ($array as $k => $v) {
if(strcasecmp($k, $key) === 0) {
return $array[$k];
} elseif(is_array($v) && ($find = &findByKey($array[$k], $key))) {
return $find;
}
}
return null;
}
$result = &findByKey($array, 'key3');
$result = 'changed';
print_r($array);
using array_search in a 1 dimensional array is simple
$array = array("apple", "banana", "cherry");
$searchValue = "cherry";
$key = array_search($searchValue, $array);
echo $key;
but how about an multi dimensional array?
#RaceRecord
[CarID] [ColorID] [Position]
[0] 1 1 3
[1] 2 1 1
[2] 3 2 4
[3] 4 2 2
[4] 5 3 5
for example i want to get the index of the car whose position is 1. How do i do this?
In php 5.5.5 & later versions,
you can try this
$array_subjected_to_search =array(
array(
'name' => 'flash',
'type' => 'hero'
),
array(
'name' => 'zoom',
'type' => 'villian'
),
array(
'name' => 'snart',
'type' => 'antihero'
)
);
$key = array_search('snart', array_column($array_subjected_to_search, 'name'));
var_dump($array_subjected_to_search[$key]);
Output:
array(2) { ["name"]=> string(5) "snart" ["type"]=> string(8) "antihero" }
working sample : http://sandbox.onlinephpfunctions.com/code/19385da11fe0614ef5f84f58b6dae80bd216fc01
Documentation about array_column can be found here
function find_car_with_position($cars, $position) {
foreach($cars as $index => $car) {
if($car['Position'] == $position) return $index;
}
return FALSE;
}
You can try this
array_search(1, array_column($cars, 'position'));
Hooray for one-liners!
$index = array_keys(array_filter($array, function($item){ return $item['property'] === 'whatever';}))[0];
Let's make it more clear:
array_filter(
$array,
function ($item) {
return $item['property'] === 'whatever';
}
);
returns an array that contains all the elements that fulfill the condition in the callback, while maintaining their original array keys. We basically need the key of the first element of that array.
To do this we wrap the result in an array_keys() call and get it's first element.
This specific example makes the assumption that at least one matching element exists, so you might need an extra check just to be safe.
I basically 'recreated' underscore.js's findWhere method which is to die for.
The function:
function findWhere($array, $matching) {
foreach ($array as $item) {
$is_match = true;
foreach ($matching as $key => $value) {
if (is_object($item)) {
if (! isset($item->$key)) {
$is_match = false;
break;
}
} else {
if (! isset($item[$key])) {
$is_match = false;
break;
}
}
if (is_object($item)) {
if ($item->$key != $value) {
$is_match = false;
break;
}
} else {
if ($item[$key] != $value) {
$is_match = false;
break;
}
}
}
if ($is_match) {
return $item;
}
}
return false;
}
Example:
$cars = array(
array('id' => 1, 'name' => 'Toyota'),
array('id' => 2, 'name' => 'Ford')
);
$car = findWhere($cars, array('id' => 1));
or
$car = findWhere($cars, array(
'id' => 1,
'name' => 'Toyota'
));
I'm sure this method could easily reduce LOC. I'm a bit tired. :P
actually all array functions are designed for single dimension array.You always need to keep in mind that you are applying it on single dimension array.
function find_car_with_position($cars, $position) {
for($i=0;$i<count($cars);$i++){
if(array_search($search_val, $cars[$i]) === false){
// if value not found in array.....
}
else{
// if value is found in array....
}
}
}
Imagine the following multi-dimensional array:
$a = array(
'key' => 'hello',
'children' => array(
array(
'key' => 'sub-1'
),
array(
'key' => 'sub-2',
'children' => array(
array(
'key' => 'sub-sub-1'
)
)
)
)
);
I require a function that recursively runs through such an array and then finally returns a chain of all the values of a certain sub-key, using a glue string.
function collectKeyChain(array $array, $key, $parentKey, $glue){
foreach($array as $k => $v){
if(is_array($v[$parentKey]))
$children=self::collectKeyChain($v[$parentKey], $key, $parentKey, $glue, $out);
$chain[]=$glue . implode($glue, $children);
}
return $chain;
}
Called this way:
collectValueChain($a, 'key', 'children', '/');
Should then return this:
array(
'hello',
'hello/sub-1',
'hello/sub-2',
'hello/sub-2/sub-sub-1'
)
Unfortunately my brain seems completely unable to perform the task of "nested thinking". The code provided in the function above doesn't work, simply because it makes no sense. I can either use the recursive function to return an array or a string. But in the final output i require an array. On the other hand i need to chain the elements together.
That's the dilemma. And the only solution that came up in my head was using another parameter, that is passed by reference, which is an array that is being filled with the results.
Like this:
collectValueChain($a, 'key', 'children', '/', $arrayToBeFilledWithResults);
But i was unable to make even this work without getting into using multiple functions.
Perhaps it just cannot be done more easily, but i would still like to find out.
Try this one:
function collectKeyChain(array $array, $key, $parentKey, $glue) {
$return = array();
foreach ($array as $k => $v) {
if ($k == $key) {
$base = $v;
$return[] = $base;
} elseif ($k == $parentKey && is_array($v)) {
foreach ($v as $_v) {
$children = collectKeyChain($_v, $key, $parentKey, $glue);
foreach ($children as $child) {
$return[] = $base . $glue . $child;
}
}
}
}
return $return;
}
Note that if this is to be a static method in a class you have to add self:: to the recursive method call.
A more simple version, without lots of foreach. Consider the second approach:
collectValueChain($a, 'key', 'children', '/', $arrayToBeFilledWithResults);
I do this:
function collectValueChain($a, $keyname, $parent, $glue, &$rtn, $pre="") {
$_pre = "";
if ($a[$keyname]) {
$rtn[] = $_pre = $pre.$glue.$a[$keyname];
}
if ($a[$parent]) {
if(is_array($a[$parent])) {
foreach($a[$parent] as $c)
collectValueChain($c, $keyname, $parent, $glue, $rtn, $_pre );
} else {
collectValueChain(a[$parent], $keyname, $parent, $glue, $rtn, $_pre );
}
}
$qtd = count($rtn);
return $rtn[-1];
}