I have a multi array e.g
$a = array(
'key' => array(
'sub_key' => 'val'
),
'dif_key' => array(
'key' => array(
'sub_key' => 'val'
)
)
);
The real array I have is quite large and the keys are all at different positions.
I've started to write a bunch of nested foreach and if/isset but it's not quite working and feels a bit 'wrong'. I'm fairly familiar with PHP but a bit stuck with this one.
Is there a built in function or a best practise way that I can access all values based on the key name regardless of where it is.
E.g get all values from 'sub_key' regardless of position in array.
EDIT: I see now the problem is that my "sub_key" is an array and therefore not included in the results as per the first comment here http://php.net/manual/en/function.array-walk-recursive.php
Just try with array_walk_recursive:
$output = [];
array_walk_recursive($input, function ($value, $key) use (&$output) {
if ($key === 'sub_key') {
$output[] = $value;
}
});
Output:
array (size=2)
0 => string 'val' (length=3)
1 => string 'val' (length=3)
You can do something like
$a = [
'key' => [
'sub_key' => 'val'
],
'dif_key' => [
'key' => [
'sub_key' => 'val'
]
]
];
$values = [];
array_walk_recursive($a, function($v, $k, $u) use (&$values){
if($k == "sub_key") {
$values[] = $v;
}
}, $values );
print_r($values);
How does it work?
array_walk_recursive() walks by every element of an array resursivly and you can apply user defined function. I created an anonymous function and pass an empty array via reference. In this anonymous function I check if element key is correct and if so it adds element to array. After function is applied to every element you will have values of each key that is equal to "sub_key"
Related
I have an array with an index. The index is not static and keeps changing.
$fields = [
11 => array (
'fieldId' => 'ORStreet',
'type' => 'TEXT',
'value' => 'Postbus 52',
),
];
Index of the above one is 11. But sometimes it becomes a different number.
One thing that always stays the same is the fieldId. How can i get the index of this array by only knowing the field id.
This above array is a child of the main array called 'fields'.
In my head i have something like this:
Loop through the main array called fields > if you find an array with fieliD => ORStreet. Return the index of that array.
If its not possible to get an index this way, i wouldnt mind if I got the 'value' => 'Postbus52' key-pair.
<?php
$arr = [
[
'fieldId' => 'ORStreet',
'type' => 'TEXT',
'value' => 'Postbus 52',
],
[
'fieldId' => 'vbnm',
'type' => 'TEXT',
'value' => 'Postbus 52',
],
[
'fieldId' => 'ORStreet',
'type' => 'TEXT',
'value' => 'Postbus 52',
]
];
shuffle($arr);
foreach ($arr as $key => $value) {
if(array_key_exists("fieldId", $value) && $value["fieldId"] === "ORStreet"){
echo $key;
break;
}
}
?>
I have used shuffle method to simulate randomness of the array. Then I have loop through the array to match fieldId with specified value(ORStreet) . If it got match then the loop will terminates and display the index.
Another Way:
$filteredArr = array_pop(array_filter($arr, function ($a){
return array_key_exists("fieldId", $a) && $a["fieldId"] === "ORStreet";
}));
You can use combination of array_map() and array_flip()
$index = array_flip(array_map(function($val){
return $val["fieldId"];
}, $arr));
echo $index["ORStreet"];
// output: 11
Check result in demo
One more possibility:
$result = array_keys(
array_combine(array_keys($fields), array_column($fields, "fieldId")),
"ORStreet"
);
array_column() extracts all the fieldId values, and then array_keys() searches for your desired value, returning the relevant array keys.
Note this will return an array of keys. If you only want the first key, this will return it as an integer:
$result = array_search(
"ORStreet",
array_combine(array_keys($fields), array_column($fields, "fieldId"))
);
I'm using array_filter in PHP to split an array containing multiple arrays when the value of a key named type matches a specific string. Here's what this looks like:
Sample Array
$arr[] = Array (
[0] => Array ( [type] => Recurring ... )
[1] => Array ( [type] => Single ... )
)
Functions
function recurring($value)
{
return ($value['type'] == 'Recurring');
}
function single($value)
{
return ($value['type'] == 'Single');
}
Split Arrays
$recurring = array_filter($arr, 'recurring');
$single = array_filter($arr, 'single');
This works, but I was curious if there was a way to simplify it so that I could create additional filtered arrays in the future without creating a new function for each.
I've started setting up a single function using a closure, but I'm not sure how to do it. Any ideas?
function key_type($value, $key, $string) {
return $key == 'type' && $value == $string;
}
$recurring = array_filter($arr,
key_type('Recurring'), ARRAY_FILTER_USE_BOTH);
$single = array_filter($pricing,
key_type('Single'), ARRAY_FILTER_USE_BOTH);
You could actually do what you proposed in your question. You just need to have the key_type() function return a callable function, which is what array_filter expects as the second parameter. You can return an anonymous function and pass the argument into the anonymous function using the use keyword as CBroe mentioned in the comments.
Here is an example:
function key_type($key) {
return function($value) use ($key) {
return $value['type'] == $key;
};
}
$arr = array(
array('type'=>'Recurring'),
array('type'=>'Single')
);
print_r(array_filter($arr, key_type('Single'), ARRAY_FILTER_USE_BOTH));
The above code will output:
Array ( [1] => Array ( [type] => Single ) )
The beauty of this method is that if you need to change the logic for all instances where you need to use your filter, you just have to change it one time in your key_type function.
An approach would be like below, however I don't like it honestly.
$array = [['type' => 'Single'], ['type' => 'Recurring']];
function key_type($value) {
global $string;
return $value['type'] == $string;
}
($string = 'Recurring') && ($recurring = array_filter($array, 'key_type'));
($string = 'Single') && ($single = array_filter($array, 'key_type'));
Another way to achieve same thing is using Anonymous functions (closures). Don't think much about being DRY it seems nice:
$array = [['type' => 'Single'], ['type' => 'Recurring']];
$recurring = array_filter($array, function($value) {
return $value['type'] == 'Recurring';
});
$single = array_filter($array, function($value) {
return $value['type'] == 'Single';
});
This task might be more about grouping than filtering -- it is difficult to discern from the limited sample data.
As a general rule, I strongly advise against using variable variables in PHP code. It is better practice to store data in arrays for accessibility reasons.
If you only have the two mentioned type values in your project data, then the conditional can be removed entirely.
Code: (Demo)
$array = [
['type' => 'Recurring', 'id' => 1],
['type' => 'Single', 'id' => 2],
['type' => 'Other', 'id' => 3],
['type' => 'Recurring', 'id' => 4],
['type' => 'Single', 'id' => 5],
];
$result = [];
foreach ($array as $row) {
if (in_array($row['type'], ['Recurring', 'Single'])) {
$result[strtolower($row['type'])][] = $row;
}
}
var_export($result);
Output:
array (
'recurring' =>
array (
0 =>
array (
'type' => 'Recurring',
'id' => 1,
),
1 =>
array (
'type' => 'Recurring',
'id' => 4,
),
),
'single' =>
array (
0 =>
array (
'type' => 'Single',
'id' => 2,
),
1 =>
array (
'type' => 'Single',
'id' => 5,
),
),
)
I have below multidimensional array and I want to replace value of
$data['meta']['attr']['road'] with an array ['test']
Thing is I don't know keys they are only available through keys array
$keys = ['meta', 'attr', 'road'];
This is just an example keys might be anything hence want to search each element, check it and replace if key is found
My multidimensional array is below:
$data = ['meta' => [
'time' => 11.364,
'count' => 3,
'attr' => [
'id'=> 7845,
'road' => [
'length' => 'km',
'width' => 'm'
]
]
],
'Assets' => [15,78,89]
];
Looks complicated search and replace algorithm really stuck ...any thoughts?
$keys = ['meta', 'attr', 'road'];
$arr = &$data;
foreach($keys as $key)
{
$arr = &$arr[$key];
}
$arr = ['test'];
You can access multidimensional array values using brackets and keys.
// set
$someArray['key']['key'] = 'value';
// get
$someVar = $someArray['key']['key'];
See arrays section on Php reference
So in your case it is;
$data['meta']['attr']['road'] = array('test' => 'value');
I have two arrays:
$array = [
'application' => [
'foo' => [
'bar' => 1
]
]
];
$array_2 = [
0 => 'application',
1 => 'foo',
2 => 'bar'
];
How can I change the value of the first array knowning that the last key in the second array is the key who's value must be changed in the first array?
As you can see the second array contains all the keys from the first array. I want to do something like:
$array[$array_2] = 2;
... I suppose I must create a for loop?
For example, if I want to change the bar key value, I must do:
$array['application']['foo']['bar'] = 2;
... but I don't know which key I must change, I only have an array containing keys, and the last key in the list is the key that's value must be changed.
You could build a recursive function, or use a reference:
$result =& $array;
foreach($array_2 as $key) {
$result =& $result[$key];
}
$result = 2;
print_r($array);
This will do it, although not sure what you are trying to achieve.
$array[$array_2[0]][$array_2[1]][$array_2[2]] = 2;
Recursively add the keys. This works -
function get_keys($arr, &$keys){
$keys = array_merge($keys,array_keys($arr));
foreach($arr as $a){
if(is_array($a)){
get_keys($a, $keys);
}
}
}
$array = Array(
'application' => Array(
'foo' => Array(
'bar' => 1
)
)
);
$keys = Array();
get_keys($array, $keys);
var_dump($keys);
OUTPUT-
array
0 => string 'application' (length=11)
1 => string 'foo' (length=3)
2 => string 'bar' (length=3)
Consider an associative array of arbitrary form and nesting depth, for example:
$someVar = array(
'name' => 'Dotan',
'age' => 35,
'children' => array(
0 => array(
'name' => 'Meirav',
'age' => 6,
),
1 => array(
'name' => 'Maayan',
'age' => 4,
)
),
'dogs' => array('Gili', 'Gipsy')
);
I would like to convert this to an associative array of paths and values:
$someVar = array(
'name' => 'Dotan',
'age' => 35,
'children/0/name' => 'Meirav',
'children/0/age' => 6,
'children/1/name' => 'Maayan',
'children/1/age' => 4,
'dogs/0' => 'Gili',
'dogs/1' => 'Gipsy'
);
I began writing a recursive function which for array elements would recurse and for non-array elements (int, floats, bools, and strings) return an array $return['path'] and $return['value']. This got sloppy quick! Is there a better way to do this in PHP? I would assume that callables and objects would not be passed in the array, though any solution which deals with that possibility would be best. Also, I am assuming that the input array would not have the / character in an element name, but accounting for that might be prudent! Note that the input array could be nested as deep as 8 or more levels deep!
Recursion is really the only way you'll be able to handle this, but here's a simple version to start with:
function nested_values($array, $path=""){
$output = array();
foreach($array as $key => $value) {
if(is_array($value)) {
$output = array_merge($output, nested_values($value, (!empty($path)) ? $path.$key."/" : $key."/"));
}
else $output[$path.$key] = $value;
}
return $output;
}
function getRecursive($path, $node) {
if (is_array($node)) {
$ret = '';
foreach($node as $key => $val)
$ret .= getRecursive($path.'.'.$key, $val);
return $ret;
}
return $path.' => '.$node."\n";
}
$r = getRecursive('', $someVar);
print_r($r);
All yours to place it in an array.