Merge/Flatten 3rd level data to create an array of arrays - php

I have an array with 3 levels and I'd like to merge/flatten all 3rd level subarrays into one subarray/row on the 2nd level.
$array = [
[
'User' => [
'id' => 57341,
'updated' => null,
'userId' => 57341,
'value' => null,
'lat' => 53.4537812,
'lon' => -2.1792437,
],
[
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
],
[
'User' => [
'id' => 57336,
'updated' => null,
'userId' => 57336,
'value' => null,
'lat' => 53.473684,
'lon' => -2.2399827,
],
[
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
],
];
The deep User-keyed subarrays (having 6 elements) should be merged with its sibling/indexed subarray (having 3 elements) to form a 9-element row on the second level.
Desired result:
[
[
'id' => 57341,
'updated' => null,
'userId' => 57341,
'value' => null,
'lat' => 53.4537812,
'lon' => -2.1792437,
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
],
[
'id' => 57336,
'updated' => null,
'userId' => 57336,
'value' => null,
'lat' => 53.473684,
'lon' => -2.2399827,
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
]

You can use splat ... operator with array_merge
foreach($a as $child){
$flatten[] = array_merge(...$child);
}
Working example :- https://3v4l.org/HkUh6

To merge and flatten the 3rd level data sets into consolidated 2nd level rows with functional style programming, make iterated calls of array_merge() which receive all 3rd level payloads at once. The spread operator (...) is a concise technique used to unpack multiple elements in an array. A special consideration is needed for this case because spreading elements which have non-numeric keys will cause code breakage. To overcome this, simply call array_values() to "index" the array (replace all keys with sequenial numbers) before spreading.
Code: (Demo)
var_export(
array_map(
fn($rows) => array_merge(...array_values($rows)),
$array
)
);

Slightly different to your example output, but you can merge your inner arrays.
<?php
$data =
[
[
'animal' => [
'type' => 'fox'
],
[
'colour' => 'orange'
]
],
[
'animal' => [
'type' => 'panda'
],
[
'colour' => 'black and white'
]
]
];
$result =
array_map(
function($v) {
return array_merge($v['animal'], $v[0]);
},
$data
);
var_export($result);
Output:
array (
0 =>
array (
'type' => 'fox',
'colour' => 'orange',
),
1 =>
array (
'type' => 'panda',
'colour' => 'black and white',
),
)

If I understood you correctly you need to merge User array and in this case with the second array in that key. it that case something like this should work
foreach($array as $key=>$deep1){
$newArray = [];
foreach($deep1 as $deep2){
$newArray = array_merge($newArray,$deep2)
}
$array[$key] = $newArray;
}
Did II understand your question correctly?

Related

array_merge removes a empty string

There's a thing that I don't understand when I use array_merge() :
$defaultOptions = [
'active' => null,
'activeClass' => 'active',
'wrapper' => [
'attributes' => null,
'templateVars' => null
],
'item' => [
'hasChildrenClass' => '', // this disappears after array_merge
'attributes' => null,
'linkAttrs' => null,
'templateVars' => null
]
];
$options = [
'active' => [5,3],
'item' => [
'attributes' => ['class' => 'test']
]
];
$options = array_merge($defaultOptions, $options);
The result of $options is
[
'active' => [
(int) 0 => (int) 5,
(int) 1 => (int) 3,
],
'activeClass' => 'active',
'wrapper' => [
'attributes' => null,
'templateVars' => null,
],
'item' => [
'attributes' => [
'class' => 'test',
],
],
]
I don't understand why $options['item']['hasChildrenClass'] disappeared in my result ?
In array_merge() if the arrays have the same string keys, then values from the later arrays will overwrite the previous one. If the arrays have numeric keys, then values from the later arrays will appended with previous one. If the arrays contain null or empty values, this value will be skipped and removed from the merged array.
Read more at php.net manual

How to transform nested array to a flat array of nodes PHP?

I have a nested array with a structure as detailed below.
It is an org chart where an employ could have other employees related:
$tree_array = [
[
'id' => 1,
'employee' => 'John',
'leader_id' => NULL,
'team' => [
[
'id' => 2,
'employee' => 'Maria',
'leader_id' => 1,
'team' => [],
],
[
'id' => 3,
'employee' => 'Kevin',
'leader_id' => 1,
'team' => [
[
'id' => 4,
'employee' => 'Alan',
'leader_id' => 3,
'team' => [],
],
[
'id' => 5,
'employee' => 'Bret',
'leader_id' => 3,
'team' => [],
],
],
],
],
]
];
Every node has an ID and a team, that could be an array of other nodes and so on.
I need to obtain each node in a flat array, like this structure:
$flat_array = array(
array(
'id' => 1,
'employee' => 'John',
'leader_id' => NULL
),
array(
'id' => 2,
'employee' => 'Maria',
'leader_id' => 1
),
array(
'id' => 3,
'employee' => 'Kevin',
'leader_id' => 1
),
...
);
I've tried to implement a recursive function, but I get only the nodes of the last iteration.
Any help?
You can make a recursive function, like this:
function flatten($arr, $final=array()) {
foreach($arr as $a) {
$tmp = $a;
unset($tmp['team']);
$final[]= $tmp;
if ($a['team'] && count($a['team']) > 0) $final = flatten($a['team'], $final);
}
return $final;
}
$flat =flatten($tree_array);
Test it here: https://www.tehplayground.com/UHWCccFIkrS5v75Z

Search in multidimensional array by several values

I have an array which I'm sure there are some duplicate values in it, I want to search in this array and find the duplicate values and return the key of that array.
let me explain with an example, this is my array:
[
0 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => 10
],
1 => [
'name' => 'name1',
'family' => 'family1',
'email' => 'email1#sample.com',
'rate' => 4
],
2 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => 6
]
];
Now, I want to search in this array by name, family, and email at the same time and return the key of the parent (in this example 0 and 2). because I want to create a new array like this :
[
0 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => [
10,
6
]
],
1 => [
'name' => 'name1',
'family' => 'family1',
'email' => 'email1#sample.com',
'rate' => [
4
]
],
];
How can I do this in PHP?
You can use array-reduce and use the 3 similar fields as keys.
Define a function who create the key and set or add rate:
function combineRate($carry, $item) {
$k = implode('###', array($item['name'], $item['family'], $item['email']));
if (isset($carry[$k]))
$carry[$k]['rate'][] = $item['rate'];
else {
$item['rate'] = [$item['rate']];
$carry[$k] = $item;
}
return $carry;
}
Call it with empty array:
$res = array_values(array_reduce($a, 'combineRate', array()));
Live example: 3v4l

Sort multi-dimensional array so specific sub-array is first

I want to sort an array so that a specific array with a specific value is shown as the first in the array.
The array I have:
array = [
[0] => [
'id' => 123,
'name' => 'Random'
],
[1] => [
'id' => 156,
'name' => 'keyboard'
],
[2] => [
'id' => 12235,
'name' => 'Text'
],
];
I want the sub-array where the name is 'keyboard' to be the first in line of the big array.
Does anyone have suggestions?
usort Sort an array by values using a user-defined comparison function
$array = [
0 => [
'id' => 123,
'name' => 'Random'
],
1 => [
'id' => 156,
'name' => 'keyboard'
],
2 => [
'id' => 12235,
'name' => 'Text'
],
];
usort($array, function ($item) {
return $item['name'] != 'keyboard';
});
print_r($array);
See the demo
$myArray = [
[0] => [
'id' => 123,
'name' => 'Random'
],
[1] => [
'id' => 156,
'name' => 'keyboard'
],
[2] => [
'id' => 12235,
'name' => 'Text'
],
];
$temp = $myArray[0];
$myArray[0] = $myArray[1];
$myArray[1] = $temp;

Merge rows of two arrays containing objects by first level index

I am trying to merge the results of two CodeIgniter queries. The trouble is that the two arrays contain rows of objects and array_merge() does not work on objects. How can I merge the two object arrays.
Input:
$array1 = [
(object) [
'trainerid' => 1,
'firstname' => 'abc',
'location' => 'area',
'photo' => 'abc.jpg',
'role' => 'user',
'city' => 'bangalore',
],
(object) [
'trainerid' => 2,
'firstname' => 'abcd',
'location' => 'area',
'photo' => 'abcd.jpg',
'role' => 'user',
'city' => 'bangalore',
],
];
$array2 = [
(object) [
'rating' => 3.0000,
'users' => 0,
'review' => 0
],
(object) [
'rating' => 4.0000,
'users' => 4,
'review' => 5
]
];
Desired output:
array (
0 =>
(object) array(
'trainerid' => 1,
'firstname' => 'abc',
'location' => 'area',
'photo' => 'abc.jpg',
'role' => 'user',
'city' => 'bangalore',
'rating' => 3.0,
'users' => 0,
'review' => 0,
),
1 =>
(object) array(
'trainerid' => 2,
'firstname' => 'abcd',
'location' => 'area',
'photo' => 'abcd.jpg',
'role' => 'user',
'city' => 'bangalore',
'rating' => 4.0,
'users' => 4,
'review' => 5,
),
)
You've made a relatively basic task much harder to do by using CodeIgniter's ->result() instead of ->result_array(). If you had arrays of arrays, then you could just use array_map('array_merge', $array1, $array2), but that will not work with your object arrays.
Instead, you'll need to call get_object_vars() on each object (and you are going to be iterating multiple objects inside the outer array_map().
Essentially, this task is a matter of iterating both arrays simultaneously, casting each pair of objects to array type, then merging the arrays, then casting the merged array back to object type.
The following snippet is designed with the flexibility to process 2 or more object arrays.
Code: (Demo)
var_export(
array_map(
fn(...$objs) => (object) array_merge(...array_map('get_object_vars', $objs)),
$array1,
$array2
)
);
The above can be written a little more concisely when only two object arrays are being merged. (Demo)
var_export(
array_map(
fn($obj1, $obj2) => (object) array_merge((array) $obj1, (array) $obj2),
$array1,
$array2
)
);
A classic nested foreach approach can be used to avoid casting and recasting data types while merging. array_merge() and array_merge_recursive() cannot (currently) be used to merge objects together -- their properties must be individually defined in the receiving object. (Demo)
$result = [];
foreach ($array1 as $i => $obj1) {
$result[$i] = $obj1;
foreach ($array2[$i] as $k => $v) {
$result[$i]->$k = $v;
}
}
var_export($result);
Output from any of the above snippets:
array (
0 =>
(object) array(
'trainerid' => 1,
'firstname' => 'abc',
'location' => 'area',
'photo' => 'abc.jpg',
'role' => 'user',
'city' => 'bangalore',
'rating' => 3.0,
'users' => 0,
'review' => 0,
),
1 =>
(object) array(
'trainerid' => 2,
'firstname' => 'abcd',
'location' => 'area',
'photo' => 'abcd.jpg',
'role' => 'user',
'city' => 'bangalore',
'rating' => 4.0,
'users' => 4,
'review' => 5,
),
)
You need to use array_map along with the array_merge like as
print_r(array_map('array_merge', $arr1, $arr2));
You can have something like :
Let's assume $a is your first array and $b is the second one and $c will be your desired output.
$c = array();
for($i=0;$i<count($a);$i++){
$c[$i] = array_merge($a[$i],$b[$i]);
}

Categories