I have this ff. assoc array
$array = [
'school' => [
'college' => [
'nursing' => ['n1a', 'n2a', 'n3a', 'n4a'],
'hrm' => ['h1a', 'h2a', 'h3a', 'h4a'],
'tourism' => ['t1a', 't2a', 't3a', 't4a'],
'it' => ['i1a', 'i2a', 'i3a', 'i4a'],
],
'senior' => [],
],
'business' => [
'office' => [
'dep1' => ['team1', 'team2'],
'dep2' => ['team1', 'team2'],
'dep3' => ['team1', 'team2'],
'dep4' => ['team1', 'team2'],
],
],
]
And I have this code, but this only search first level array.
function searchItemsByKey($array, $key) {
$results = array();
if (is_array($array))
{
if (isset($array[$key]) && key($array)==$key){
$results[] = $array[$key];
}
foreach ($array as $sub_array){
$results = array_merge($results, $this->searchItemsByKey($sub_array, $key));
}
}
return $results;
}
All I want is to search all keys in this array that will result all arrays associated with keys like:
searchItemsByKey($array, 'hrm');
That will return:
['h1a', 'h2a', 'h3a', 'h4a']
Thanks.
You can use array_walk_recursive,
$result = [];
$search = "hrm";
function searchItemsByKey($array, $key)
{
$retArr = [];
if (is_array($array)) {
if (!empty($array[$key])) {
return $array[$key];
}
foreach ($array as $val) {
$retArr = array_merge($retArr, searchItemsByKey($val, $key));
}
}
return $retArr;
}
$temp = searchItemsByKey($array, 'hrm');
Demo.
Related
I have a multidimensional array like this:
array (
level1 => array ( level1.1,
level1.2)
level2 => array ( level2.1,
level2.2 => array( level2.2.1 => 'foo',
level2.2.2 => 'bar',
level2.2.3 => 'test')
)
)
As a result I want an array of strings like this
array ("level1/level1.1",
"level1/level1.2",
"level2/level2.1",
"level2/level2.2/level2.2.1",
"level2/level2.2/level2.2.2",
"level2/level2.2/level2.2.3")
Here is the code I tried
function displayArrayRecursively($array, string $path) : array {
if($path == "")
$result_array = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$this->displayArrayRecursively($value, $path . $key . '/');
} else {
$result_array[] = $path . $key; }
}
return $result_array;
}
Any idea how I can achieve this. I could use a reference array to populate, but I want to solve it with return values.
$array = [
'level1' => [
'level1.1',
'level1.2'
],
'level2' => [
'level2.1',
'level2.2' => [
'level2.2.1' => 'foo',
'level2.2.2' => 'bar',
'level2.2.3' => 'test'
]
]
];
function arrayParser(array $array, ?string $path=null) {
$res = [];
foreach($array as $key => $value) {
if(is_array($value)) {
$res[] = arrayParser($value, ($path ? $path.'/' : $path).$key);
}
else {
$res[] = $path.'/'.(!is_numeric($key) ? $key : $value);
}
}
return flatten($res);
}
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
$res = arrayParser($array); // result
I have the code if there is the same name in 2nd foreach, then the same name is not displayed, but I don't know how to keep the same name not displayed?.
$arr = [];
foreach ($respon_tel['item'] as $item) {
$proyek = [
'nama_proyek' => $item['judul_kontrak'],
'from' => 'Another API'
];
foreach($model as $m){
if(trim(strtolower($item['judul_kontrak'])) == trim(strtolower($m['nama_proyek']))){
// ????
}
}
$arr[] = $proyek;
}
return $arr;
You can get all the nama_proyek's from the $model then you can check if the current $item's judul_kontrak is in that set:
$models = collect($model)
->map(fn ($i) => trim(strtolower($i['nama_proyek'])));
foreach ($respon_tel['item'] as $item) {
if (! $models->contains(trim(strtolower($item['judul_kontrak'])))) {
$arr[] = [
'nama_proyek' => $item['judul_kontrak'],
'from' => 'Another API'
];
}
}
Or you could get creative with the Collection methods:
collect($respon_tel['item'])
->pluck('judul_kontrak', 'judul_kontrak')
->map($f = fn ($item) => trim(strtolower($item)))
->diff(
collect($model)->pluck('nama_proyek')->map($f)
)->map(function ($item, $key) {
return [
'nama_proyek' => $key,
'from' => 'Another API',
];
})->values();
I have two arrays. $array2 to check whether $array1 value exist in 'slug'.
$array1 = [
0 => "tenants",
1 => "modules",
];
$array2 = [
"child" => [
"prefix" => "tenants",
"slug" => "tenants",
"child" => [
[
"prefix" => "modules/{id}",
"slug" => "modules"
],
[
"prefix" => "fetch/{id}",
"slug" => "fetch"
],
],
],
];
My Code:
foreach ($array1 as $value) {
array_walk_recursive($array2['child'],
function ($item, $key) use (&$result, &$res, &$value) {
if ($key == "slug") {
if ($item == $value) {
$res[] = $item;
}
}
if ($key == 'prefix') {
$result[] = $item;
}
});
}
Here I used array_walk_recursive to check every if array1 is exist in slug. But i want to get also it's prefix.
In my code above It will not get the modules/{id} since it's not equal to slug.
Example:
$array1 = [
0 => "tenants",
1 => "modules",
];
Result:
array:3 [▼
1 => "tenants"
2 => "modules/{id}"
]
Code: https://3v4l.org/E18Uq
Happy coding.
You don't need to use array_walk_recursive just use custom function as:
function getFromChild($item, $asd) {
if (!is_array($item)) return [];
$res = [];
if ($item["slug"] == $asd) // if have slug check and add if needed
$res[] = $item['prefix'];
if (isset($item['child']))
foreach($item['child'] as $child) // for all child loop and add
$res = array_merge($res, getFromChild($child, $asd));
return $res;
}
Now you can call it with:
$res = [];
foreach ($array1 as $asd) {
$res = array_merge($res, getFromChild($array2, $asd));
}
Live example: 3v4l
Having this recursive function ($key can be numeric as array(0=>'value1',1=>'value2' or string as array('key1'=>'value1','key2'=>'value2')), being $key,
needle and $array haystack:
public function array_key_search($searched_key, $array = array()){
* #param $searched_key: Key to search.
* $array: Array with keys to check.
* Recursive method to check if a key exists in a multidemensional array.
* If key exists, it returns corresponding value.
*/
foreach($array as $key => $value){
$key = "$key";
if($key_value == false){
if($key == $searched_key){
return $value;
}else{
if(is_array($value)){
$key_value = self::array_key_search($searched_key, $value);
}
}
}
}
$key_value == is_null($key_value) ? false : $key_value;
return $key_value;
}
May I use if($key === $searched_key) instead of invoking my $key param as string for comparision?
This time I'm talking about performance because this function may be hard to process sometimes.
This does what you want
$arr = [
'key1' => [
'key1.1' => [
'key1.1.1' => 'key1.1.1',
'key1.1.2' => 'key1.1.2'
],
'key1.2' => [
'key1.2.1' => 'key1.2.1',
'key1.2.2' => 'key1.2.2'
],
],
'key2' => [
'key2.1' => [
'key2.1.1' => 'key2.1.1',
'key2.1.2' => 'key2.1.2'
]
]
];
function get_key_val($search_key, $arr){
foreach($arr as $key => $value){
if( is_array($value) ){
$result = get_key_val($search_key, $value);
if ($result){
return $result;
}
}else{
if ($search_key == $key){
return $value;
}
}
}
return null;
}
var_dump(get_key_val('key2.1.2', $arr));
RETURNS
string(8) "key2.1.2"
I have an array:
$arr = [
['id'=>1, 'name'=>'Peter', 'age'=>28],
['id'=>1, 'name'=>'David', 'age'=>28],
['id'=>2, 'name'=>'John', 'age'=>34],
['id'=>3, 'name'=>'Smith', 'age'=>36],
['id'=>3, 'name'=>'Smith', 'age'=>28],
];
I want filter it by column 'id', and merge the different values. I need output:
$arr = [
['id'=>1, 'name'=>'Peter,David', 'age'=>28],
['id'=>2, 'name'=>'John', 'age'=>34],
['id'=>3, 'name'=>'Smith', 'age'=>'36,28']
];
Is there any PHP function (such as: array_filter, array_walk, array_map,...) to do that, without looping code as below?
function combine_row($arr){
$last = null;
foreach ($arr as $key => $a){
if ($a['id']==$last['id']){
foreach ($a as $k=>$v) {
if($v!==$last[$k]) {
$arr[$key][$k].=','.$last[$k];
}
}
unset($arr[$key-1]);
}
$last = $a;
}
return $arr;
}
Thanks for helping me!
Here is a solution that uses a more functional style. Basically just a lot of the built-in array_* functions. This will ensure less side-effects, making your code less error prone.
The code first finds all unique _id_s. It then filters through the data and joins it in the end.
$result = array_map(
function ($id) use ($arr) {
return array_map(function ($data) {
if (is_array($data)) return join(",", array_unique($data));
return $data;
}, array_reduce(
array_filter($arr, function ($item) use ($id) { return $id === $item["id"]; }),
function ($result, $set) { return $result = array_filter(array_merge_recursive($result, $set)); }, [ ]
)
);
},
array_unique(array_column($arr, "id"))
);
print_r($result);
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => Peter,David
[age] => 28
)
[2] => Array
(
[id] => 2
[name] => John
[age] => 34
)
[3] => Array
(
[id] => 3
[name] => Smith
[age] => 36,28
)
)
Using a chainable apigithub you can achieve much more readable code:
$result = arr($arr)
->column("id")
->unique()
->map(
function ($id) use ($arr) {
return arr($arr)
->filter(function ($item) use ($id) { return $id === $item["id"]; })
->reduce(function ($result, $set) { return array_filter(array_merge_recursive($result, $set)); }, [])
->map(function ($data) {
if (is_array($data)) return arr($data)->unique()->join(",")->toArray();
return $data;
})->toArray();
}
)->toArray();
$result = [];
foreach ($arr as $person) {
foreach ($person as $key => $value) {
if ($key == 'id') {
$result[$person['id']][$key] = $value;
} else {
$result[$person['id']][$key][] = $value;
}
}
}
The magic really is in $result[$person['id']], which groups all items with the same id into the same result array very naturally. This also creates arrays for multiple values instead of merely concatenating the strings, which is a much saner data structure to work with. If you only want unique values, throw in an array_unique there. If you actually need to join the items with commas, use join(',', ..) at the end somewhere.
Check this below code,
function getMergerArray($arr) {
$newArr = array();
foreach ($arr as $key => $value) {
$id = $value['id'];
$name = $value['name'];
$age = $value['age'];
if (array_key_exists($id, $newArr)) {
if (!in_array($name, $newArr[$id]['name'])) {
$newArr[$id]['name'][] = $name;
}
if (!in_array($age, $newArr[$id]['age'])) {
$newArr[$id]['age'][] = $age;
}
continue;
}
$newArr[$id]['name'][] = $name;
$newArr[$id]['age'][] = $age;
}
foreach ($newArr as $key => $value) {
$newArr[$key] = array(
'id' => $key,
'name' => implode(', ', $value['name']),
'age' => implode(', ', $value['age']),
);
}
// echo '<pre>';
// print_r($newArr);
// echo '</pre>';
return $newArr;
}
Try this
function merge_multidimensional($arr) {
$out = array();
foreach ($arr as $key => $value){
$out[] = (object)array_merge((array)$arr2[$key], (array)$value);
}
return $out;
}