PHP - make multidimensional array to array of strings from the arrays names - php

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

Related

I have a question about php search associative array

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.

How to merge array multi key to single array

I have a array multi level
$array = array("14529" => array("900" => array("87" => array() ) ) );
print_r(array_keys($array)); // result array("14529");
How to merge this array to single array
$array = array("14529", "900", "87");
Here is a function that does what you want. It is done recursively, so it doesn't matter how deep the array is.
function mergeArrayMultiKeyToSingleArray($array, $result=[])
{
foreach($array as $key => $value) {
$result[] = $key;
if(is_array($value)) {
$result = mergeArrayMultiKeyToSingleArray($value, $result);
}
}
return $result;
}
// USAGE:
$array = array("14529" => array("900" => array("87" => array() ) ) );
$array = mergeArrayMultiKeyToSingleArray($array);
// $array is now ["14529", "900", "87"]
The solution using RecursiveIteratorIterator class:
$arr = ["14529" => ["900" => ["87" => [] ] ] ];
$keys = [];
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST) as $k => $v) {
$keys[] = $k;
}
print_r($keys);
The output:
Array
(
[0] => 14529
[1] => 900
[2] => 87
)
I did this using class
class ArrayStripper
{
private $items = [];
public function strip($arrayOrItem)
{
if(is_array($arrayOrItem))
{
foreach ($arrayOrItem as $item)
{
$this->strip($item);
}
}
else
{
$this->items[] = $arrayOrItem;
}
}
public function get()
{
return $this->items;
}
}
$array = [1 , [2,3] , 4 , [[5 , 6 , 7] , [8 ,9] , 10]];
$stripper = new ArrayStripper();
$stripper->strip($array);
var_dump($stripper->get());

recursive array_key_search function PhP

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"

How can I create an associative array from a foreach loop?

$array = ["farm"=>
[
"horse"=>
[
"rabbit"=>
[
"fred1"=> "fred1",
"fred2"=> "fred2",
"fred3"=> "fred3",
"fred4"=> "fred4"
],
"raccoon"=>
["frida"=> "frida"]
]
]
];
I want to create an array from my for each loop:
$keySearch = "o";
function createList($array, $keySearch, $path) {
foreach ($array as $key => $item) {
$basePath = $path === null ? $key : $path. "/" . $key;
if(is_array($item)){
if (stripos($key, $keySearch) !== false){
$a['key'] = $key ;
$b['basePath'] = $basePath;
$result[] = array_merge_recursive ($a, $b);
}
createList($item, $keySearch, $basePath);
}
}
print_r($result);
}
createList($array, $keySearch, '');
My result is:
Array
(
[0] => Array
(
[key] => horse
[basePath] => farm/horse
)
)
Array
(
[0] => Array
(
[key] => raccoon
[basePath] => farm/horse/raccoon
)
)
What I actually expect is:
Array
(
[0] => Array
(
[key] => horse
[basePath] => farm/horse
)
[1] => Array
(
[key] => raccoon
[basePath] => farm/horse/raccoon
)
)
https://eval.in/571065
i improved your code:
function createList($array, $keySearch, $path=null) {
$result = [];
foreach ($array as $key => $item) {
$basePath = $path === null ? $key : $path. "/" . $key;
if(is_array($item)){
if (stripos($key, $keySearch) !== false) {
$result[] = ['key' => $key, 'basePath' => $basePath];
}
$result = array_merge($result, createList($item, $keySearch, $basePath));
}
}
return $result;
}
$keySearch = 'o';
$res = createList($array, $keySearch);
print_r($res);
demo
UPD: if you find all keys, not only those which points array, change code so:
function createList($array, $keySearch, $path=null) {
$result = [];
foreach ($array as $key => $item) {
$basePath = $path === null ? $key : $path. "/" . $key;
if (stripos($key, $keySearch) !== false)
$result[] = ['key' => $key, 'basePath' => $basePath];
if(is_array($item))
$result = array_merge($result, createList($item, $keySearch, $basePath));
}
return $result;
}
$keySearch = 'fr';
$res = createList($array, $keySearch);
print_r($res);
demo
You can use your same function with addition ref attribute, and append array into that attribute.
$array = ["farm"=>
[
"horse"=>
[
"rabbit"=>
[
"fred1"=> "fred1",
"fred2"=> "fred2",
"fred3"=> "fred3",
"fred4"=> "fred4"
],
"raccoon"=>
["frida"=> "frida"]
]
]
];
function createList($array, $keySearch, $path, &$out) {
foreach ($array as $key => $item) {
$basePath = $path === null ? $key : $path. "/" . $key;
if(is_array($item)){
if (stripos($key, $keySearch) !== false){
$a['key'] = $key ;
$b['basePath'] = $basePath;
$out[] = array_merge_recursive ($a, $b);
}
createList($item, $keySearch, $basePath, $out);
}
}
}
$keySearch = "o";
createList($array, $keySearch, '', $result);
print_r($result);
Demo: https://eval.in/571224
RECURSIVE ALGORITHM SOLUTION:
<?php
$array = ["farm"=>
[
"horse"=>
[
"rabbit"=>
[
"fred1"=> "fred1",
"fred2"=> "fred2",
"fred3"=> "fred3",
"fred4"=> "fred4"
],
"raccoon"=>
["john"=> "john"]
]
]
];
$jl = array();
$root = "";
function walkJarLarsData($ar, $search, $base="base-path", $pKey=""){
global $jl, $root;
if(!stristr($root, $base)){
$root .= $base;
}
foreach($ar as $key=>$val){
$pKey = $pKey?"{$pKey}":"";
if (preg_match("#" . preg_quote($search) . "#", $key)) {
$jl[] = array(
"key" => $key,
"basePath" => $root . "/{$pKey}/{$key}",
);
}
if(is_array($val)){
walkJarLarsData($val, $search, $base, $key);
}
}
return $jl;
}
var_dump(walkJarLarsData($array, "o"));
assuredly, this is the solution you seek:
<?php
$arBase = array();
$kern = "";
function arrayRecurse($ar, $search, $mainPath="base-path", $cue=""){
global $arBase, $kern;
$kern = !(stristr($kern, $mainPath))? $kern.= $mainPath : $kern;
foreach($ar as $key=>$val){
$cue = $cue?"{$cue}":"";
if (preg_match("#" . preg_quote($search) . "#", $key)) {
$arBase[] = array(
"key" => $key,
"basePath" => $kern . "/{$cue}/{$key}",
);
}
if(is_array($val)){
arrayRecurse($val, $search, $mainPath, $key);
}
}
return $arBase;
}
var_dump(arrayRecurse($array, "fr"));

Filter 2 dimensions array and merge different values in PHP

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;
}

Categories