How to merge arrays based on value in php? - php

I am having 2 arrays and i have to merge that arrays with similar values. i tried for each and basic functions of php for array merging but not getting proper result.
i tried below thing but it wont work for me as i am having multiple data in second array. as you can see in child array i am having multiple records and i want to keep that together inside base array.
$base= [
['id' => 1],
['id' => 2],
['id' => 3],
['id' => 4],
];
$child = [
['id' => 1, 'size' => 'SM'],
['id' => 1, 'size' => 'LK'],
['id' => 2, 'size' => 'XL'],
['id' => 4, 'size' => 'LG'],
['id' => 3, 'size' => 'MD'],
];
foreach(array_merge($base, $child) as $el){
$merged[$el['id']] = ($merged[$el['id']] ?? []) + $el;
}
Output :
array (
1 =>
array (
'id' => 1,
'size' => 'SM',
),
2 =>
array (
'id' => 2,
'size' => 'XL',
),
3 =>
array (
'id' => 3,
'size' => 'MD',
),
4 =>
array (
'id' => 4,
'size' => 'LG',
),
)
desired output :
array (
1 =>
array (
'id' => 1,
1 => array('size' => 'SM'),
2 => array('size' => 'LK'),
),
2 =>
array (
'id' => 2,
1 => array('size' => 'XL'),
),
3 =>
array (
'id' => 3,
1 => array('size' => 'MD'),
),
4 =>
array (
'id' => 4,
1 => array('size' => 'LG'),
),
)

Because your array $child have same key id value, and every you save the array, it always destroyed old array with same key id.
Here the working code :
<?php
$base= [
['id' => 1],
['id' => 2],
['id' => 3],
['id' => 4],
];
$child = [
['id' => 1, 'size' => 'SM'],
['id' => 1, 'size' => 'LK'],
['id' => 2, 'size' => 'XL'],
['id' => 4, 'size' => 'LG'],
['id' => 3, 'size' => 'MD'],
];
foreach(array_merge($base, $child) as $el){
if(!isset($el['size'])){ // $base doesn't have 'size' key
$merged[$el['id']] = []; // fill with empty array
}else{
$merged[$el['id']][] = $el;
}
// bellow code is for start array index from 1 instead of 0
array_unshift($merged[$el['id']],"");
unset($merged[$el['id']][0]);
}
print_r($merged);

Related

how to sort 2 associative arrays with first array order with second array in php

I have 2 associative arrays.
$a1 = array(
'blue' =>
array('id' => 2365,
'level' => 1,
'name' => 'blue'),
'black' =>
array('id' => 478,
'level' => 1,
'name' => 'black'),
'green' =>
array('id' => 698,
'level' => 1,
'name' => 'green'),
'red' =>
array('id' => 169,
'level' => 1,
'name' => 'red')
$a2= array(
'green' =>
array('id' => 452,
'level' => 1,
'name' => 'green'),
'black' =>
array('id' => 124,
'level' => 1,
'name' => 'black'),
'red' =>
array('id' => 124,
'level' => 1,
'name' => 'red'),
'blue' =>
array('id' => 145,
'level' => 1,
'name' => 'blue')
);
I want to sort my second array in the first array key order. That means I want to sorry my array of blue, black, green, red.
My desired result like:
$a2= array(
'blue' =>
array('id' => 145,
'level' => 1,
'name' => 'blue'),
'black' =>
array('id' => 124,
'level' => 1,
'name' => 'black'),
'green' =>
array('id' => 452,
'level' => 1,
'name' => 'green'),
'red' =>
array('id' => 124,
'level' => 1,
'name' => 'red'),
);
For this I am using the code :
uasort($a2, function($a, $b) use ($a1) { return array_search($a['name'], $a1) - array_search($b['name'], $a1); }
But I didn't get my desired result.
Also I tried with this:
uksort($a2, function($key1, $key2) use ($a1) {
return (array_search($key1, $a1) - array_search($key2, $a1));
});
Another method: But again, I didn't get my desired result.
$price = array();
foreach ($a2 as $key => $row) {
$price[$key] = $row['name'];
}
array_multisort($price, SORT_DESC, $a1);
I just use the following concept:
$arr2ordered = array() ;
foreach (array_keys($a1) as $key) {
$arr2ordered[$key] = $a2[$key] ;
}
After that, I got my desired result.

Merge php array with dynamic key

If I query out the array like this form:
$arr1:
0 =>
'id' => 1,
'name' => 'a'
1 =>
'id' => 2,
'name' => 'b'
2 =>
'id' => 3,
'name' => 'c'
3 =>
'id' => 4,
'name' => 'd'
$arr2:
0 =>
'id' => 1,
'parent' => '1a'
1 =>
'id' => 2,
'parent' => '2b'
2 =>
'id' => 3,
'parent' => '3c'
3 =>
'id' => 4,
'parent' => '4d'
When I need to merge these two I can done it using foreach loop.
The problem comes to when the $arr1 is dynamic data(need to use for pagination), i can't merge well using array_merge due to $arr2 is fixed data.
example:
first time:
$arr1:
0 =>
'id' => 1,
'name' => 'a'
1 =>
'id' => 2,
'name' => 'b'
$arr2:
0 =>
'id' => 1,
'parent' => '1a'
1 =>
'id' => 2,
'parent' => '2b'
2 =>
'id' => 3,
'parent' => '3c'
3 =>
'id' => 4,
'parent' => '4d'
second time:
$arr1:
0 =>
'id' => 3,
'name' => 'c'
1 =>
'id' => 4,
'name' => 'd'
$arr2:
0 =>
'id' => 1,
'parent' => '1a'
1 =>
'id' => 2,
'parent' => '2b'
2 =>
'id' => 3,
'parent' => '3c'
3 =>
'id' => 4,
'parent' => '4d'
I had try using foreach loop
foreach($arr1 as $k => $value){
$group[$k]['parent'] = $arr2[$k]['parent'];
$group[$k]['name'] = $value['name'];
$group[$k]['id'] = $value['id'];
}
It comes to the parent value does not change as $key is fixed.
The expected output should all the element in 1 array:
0 =>
'id' => 1,
'parent' => '1a'
'name'='a'
1 =>
'id' => 2,
'parent' => '2b'
'name'='b'
I think this is what you need...
The easiest way to do this is to re-index the second array with the ID as the key. I use array_column() to do this. Then use the id from $arr1 to access the parent value from the newly indexed array...
$parent = array_column($arr2, 'parent', 'id');
$group = [];
foreach($arr1 as $k => $value){
$group[$k]['parent'] = $parent[$value['id']];
$group[$k]['name'] = $value['name'];
$group[$k]['id'] = $value['id'];
}
In case $arr2 has more information, just use null as the second parameter to array_column(). Then you need to add the column name when you access that array...
$parent = array_column($arr2, null, 'id');
$group = [];
foreach($arr1 as $k => $value){
$group[$k]['parent'] = $parent[$value['id']]['parent'];
$group[$k]['name'] = $value['name'];
$group[$k]['id'] = $value['id'];
}
Try this:
foreach($arr1 as $k=>$v) {
$arr1[$k]['parent'] = $arr2[$k]['parent'];
}
print_r( $arr1 );

Group array by specific key - PHP [duplicate]

This question already has an answer here:
Creating parent-child array PHP
(1 answer)
Closed 4 years ago.
I want to group by key this array:
$arr = [
['id' => 1, 'name' => 'a'],
['id' => 2, 'parent' => 1, 'name' => 'a-child'],
['id' => 3, 'parent' => 1, 'name' => 'a-child-2'],
['id' => 4, 'name' => 'c'],
];
To be like this:
['id' => 1, 'name' => 'a', 'child' => [
['id' => 2, 'parent' => 1, 'name' => 'a-child'],
['id' => 3, 'parent' => 1, 'name' => 'a-child-2'],
]],
['id' => 4, 'name' => 'c'],
or group them by specific key, which element will be a parent.
I am using PHP.
You can use this for 1 level deep.
$arr = [
['id' => 1, 'name' => 'a'],
['id' => 2, 'parent' => 1, 'name' => 'a-child'],
['id' => 3, 'parent' => 1, 'name' => 'a-child-2'],
['id' => 4, 'name' => 'c'],
];
$new = [];
foreach($arr as $key => $row) {
if(!isset($row['parent'])) $new[$row['id']] = $row;
}
foreach($arr as $key => $child) {
if(isset($child['parent'])) {
$new[$child['parent']]['child'][] = $child;
}
}
print_r($new);

Calculate percentage for each row between a column value and the sum of the entire column

I want to calculate the percentage for each row in an array based on a specific column value and the total of all values in that column.
Sample data:
$results = [
['type' => 'AA', 'count' => 4],
['type' => 'AE', 'count' => 59],
['type' => 'AF', 'count' => 13],
['type' => 'BB', 'count' => 44],
['type' => 'BC', 'count' => 16],
['type' => 'BD', 'count' => 36]
];
Desired result:
[
['type' => 'AA', 'count' => 4, 'percent' => '2%'],
['type' => 'AE', 'count' => 59, 'percent' => '34%'],
['type' => 'AF', 'count' => 13, 'percent' => '8%'],
['type' => 'BB', 'count' => 44, 'percent' => '26%'],
['type' => 'BC', 'count' => 16, 'percent' => '9%'],
['type' => 'BD', 'count' => 36, 'percent' => '21%'],
]
My code:
foreach($results as $row) {
$count = $row['count'];
$type = $row['type'];
$array[$type][] = $count;
}
Before performing the arithmetic on each row, you'll need to sum the count values for all rows (for your sample data, the total is 172).
Then loop over the rows, calculate the percentage and push the new associative rows into the new array.
Code: (Demo)
$results = [
['type' => 'AA', 'count' => 4],
['type' => 'AE', 'count' => 59],
['type' => 'AF', 'count' => 13],
['type' => 'BB', 'count' => 44],
['type' => 'BC', 'count' => 16],
['type' => 'BD', 'count' => 36]
];
$total = array_sum(
array_column($results, 'count')
); // 172
foreach($results as &$row) {
$row['percent'] = round($row['count'] / $total * 100, 0) . '%';
}
var_export($results);
Or instead of the classic loop, you can use a modern arrow function inside of array_map() to merge the new column into each row.
var_export(
array_map(
fn($row) => $row + ['percent' => round($row['count'] / $total * 100, 0) . '%'],
$results
)
);
Output (from either approach):
array (
0 =>
array (
'type' => 'AA',
'count' => 4,
'percent' => '2%',
),
1 =>
array (
'type' => 'AE',
'count' => 59,
'percent' => '34%',
),
2 =>
array (
'type' => 'AF',
'count' => 13,
'percent' => '8%',
),
3 =>
array (
'type' => 'BB',
'count' => 44,
'percent' => '26%',
),
4 =>
array (
'type' => 'BC',
'count' => 16,
'percent' => '9%',
),
5 =>
array (
'type' => 'BD',
'count' => 36,
'percent' => '21%',
),
)

Filter array rows by matching one or more key-value pairs in associative array

Suppose,
$data = array(
array('id' => 1, 'user_id' => 1, 'assignment_id' => 1, 'grade' => 90),
array('id' => 2, 'user_id' => 3, 'assignment_id' => 2, 'grade' => 85),
array('id' => 3, 'user_id' => 5, 'assignment_id' => 5, 'grade' => 66),
);
Now I want to filter the rows like following:
$rules = array(
'user_id' => 5,
'assignment_id' => 5
);
This should return the row at $data[2].
$rules = array(
'user_id' => 3,
'assignment_id' => 2,
'grade' => 85
);
will return $data[1].
Here order of keys may be different both in $data elements and $rules.
I tried with array_intersect, but that is not working for me.
If you just need to return a list of of the elements in $data which match the filtering criteria, you can use a combination of array_filter() and array_intersect_assoc() to do the job:
// build an array of your filtering criteria
$filter_array = array(
'user_id' => 3,
'assignment_id' => 5
);
// filter the array
$filtered_array = array_filter($data, function ($val_array) use ($filter_array) {
$intersection = array_intersect_assoc($val_array, $filter_array);
return (count($intersection)) === count($filter_array);
});
Note that you need PHP >= 5.3.0 to utilize the anonymous function as shown.
Here is a more modern and elegant approach.
Use arrow function syntax to allow $rules into the custom function's scope. If after associatively filtering the rules array by each encountered row there are no remaining elements, then all rules were satisfied.
Code: (Demo)
$data = [
['id' => 1, 'user_id' => 1, 'assignment_id' => 1, 'grade' => 90],
['id' => 2, 'user_id' => 3, 'assignment_id' => 2, 'grade' => 85],
['id' => 3, 'user_id' => 5, 'assignment_id' => 5, 'grade' => 66],
];
$rules = ['user_id' => 3, 'assignment_id' => 2];
var_export(
array_filter($data, fn($row) => !array_diff_assoc($rules, $row))
);
Output:
array (
1 =>
array (
'id' => 2,
'user_id' => 3,
'assignment_id' => 2,
'grade' => 85,
),
)

Categories