I have a small issue trying to compare data from 3 arrays, one of them is the source and the other 2 are the conditions.
the scenario is the next:
$array1 = array('code' => '123', 'code' => '124', 'code' => '125', 'code' => '126', 'code' => '127');
$array2 = array(
array('code1' => '123', 'country' => 'US', 'listed' => '0'),
array('code1' => '124', 'country' => 'US', 'listed' => '1'),
array('code1' => '125', 'country' => 'US', 'listed' => '1')
);
$array3 = array(
array('code2' => '123', 'country' => 'US', 'listed' => '1'),
array('code2' => '126', 'country' => 'US', 'listed' => '0'),
array('code2' => '127', 'country' => 'US', 'listed' => '1')
);
$final = array_merge($array1,$array2,$array3);
foreach ($final as $f) {
if ($f['code'] == $f['code1']) {
if ($f['listed'] > 0) {
$finalListed = $f['listed'];
}
} elseif ($f['code'] == $f['code2']) {
if ($f['listed'] > 0) {
$finalListed = $f['listed'];
}
}
$newFinalArray = array(
'code' = $finalCode,
'listed' = $finalListed,
'country' = $finalCountry
);
}
So what i need is to check first if the code from $array1 exist in $array2 and if if the code from $array2 is listed if not check on $array3 and so on.
So if the code exist on $array2 and listed is 1 update database with this values if not check $array3 if exist and listed is 1 update with the values if not update the values from $array2
The idea is that $array2 is from 1 site and $array3 is from another, so, if is not in 1 is the second if are in both keek from $array2
The problem is that i cannot get it sort, i have tried array_combine but this combines only 2 arrays and the parameters need to be exactly.
With array merge i get the 3 arrays into one, then on foreach and on apply if conditions it say that the variable is undefined.
First of all I see a lots of issue in the way arrays are declared by you
Ex -
$array1 = array('code' = > '123', 'code' = > '124', 'code' = > '125', 'code' = > '126', 'code' = > '127');
is nothing but
$array1 = array('code' => '127'); //because of same index it will only consider the last value
However I have modified your arrays and tried to prepare a solution which might be useful for you. Check it once below.
<?php
$array1 = array('123', '124', '125', '126', '127');
$array2 = array(array('code' => '123', 'country' => 'US', 'listed' => '0'), array('code' => '124', 'country' => 'US', 'listed' => '1'), array('code' => '125', 'country' => 'US', 'listed' => '1'));
$array3 = array(array('code' => '123', 'country' => 'US', 'listed' => '1'), array('code' => '126', 'country' => 'US', 'listed' => '0'), array('code' => '127', 'country' => 'US', 'listed' => '1'));
function compareSitesAndUpdate($array1, $array2, $array3) {
foreach($array1 as $code) {
if(isCodeExistsInArray($code,$array2)) {
echo $code . ' is in array2 and listed <br />';
}
else { // ;( Not in Array2 check in Array3
echo $code . ' not listed in array2 - checking in array3 <br />';
if(isCodeExistsInArray($code,$array3)) {
echo $code . ' is in array3 and listed <br />';
}
else {
echo $code . ' not listed in array3 also - do whatever you want to do <br />';
}
}
}
}
//Note $earray is always expected to be in the format of $array2/$array3
//And key of $array2 and $array3 should always be 'code' - Not necessary to change the keys are they are two diff arrays
function isCodeExistsInArray($ecode, $earray) {
foreach($earray as $code_array) {
if($ecode == $code_array['code']) { //code match found - now check if it is listed
if($code_array['listed'] == 1) { //Got what we need - return TRUE and Break
return TRUE;
}
}
}
return FALSE; //any other case return False;
}
compareSitesAndUpdate($array1, $array2, $array3);
?>
Why don't you try something like this:
foreach($array1 as $key => $code){
if(in_array($code, $array2) {
echo 'Value is in the array! :D ';
}
else {
if(in_array($code, $array3) {
echo 'Value is in array3! :D';
}
}
Suppose that you have the same key for codes in both arrays: $array2 and $array3, i.e.:
$array1 = array(
'123',
'124',
'125',
'126',
'127'
);
$array2 = array(
array('code' => '123', 'country' => 'US', 'listed' => '0'),
array('code' => '124', 'country' => 'US', 'listed' => '1'),
array('code' => '125', 'country' => 'US', 'listed' => '1')
);
$array3 = array(
array('code' => '123', 'country' => 'US', 'listed' => '1'),
array('code' => '126', 'country' => 'US', 'listed' => '0'),
array('code' => '127', 'country' => 'US', 'listed' => '1')
);
Then:
$newFinalArray = array_filter(array_merge($array2, $array3), function($el){
if($el['listed'] > 0 && in_array($el['code'], $GLOBALS['array1'])) {
return true;
}
});
Related
I got the following Array in PHP:
$data[] = array('Slug' => 'jan', 'Name' => 'Jan', 'Alter' => '39', 'Jahrgang' => '1981', 'ID' => '3');
$data[] = array('Slug' => 'kjell', 'Name' => 'Kjell', 'Alter' => '4', 'Jahrgang' => '2018', 'ID' => '0');
$data[] = array('Slug' => 'bjarne', 'Name' => 'Bjarne', 'Alter' => '6', 'Jahrgang' => '2015', 'ID' => '2');
$data[] = array('Slug' => 'monika', 'Name' => 'Monika', 'Alter' => '72', 'Jahrgang' => '1950', 'ID' => '1');
How can I output the Value of "Jahrgang" where "Slug = Jan"?
How can I change the "Jahrgang" where "Slug = Jan" from 1981 to 1982?
Is there any way without a foreach?
Thank you so much!
It can be done with pair array_search and array_column like this:
$key = array_search('jan', array_column($data, 'Slug'));
array_column returns single dimension array only with given key, in this case Slug, and then array_search returns key of this value in reduced array with should be same as in main one. So for questions it would be:
echo $data[array_search('jan', array_column($data, 'Slug'))]['Jahrgang'];
$data[array_search('jan', array_column($data, 'Slug'))]['Jahrgang'] = '1982';
I would opt to slightly restructure the data for easier access, by setting the array key to the Slug value.
$data['jan'] = array('Name' => 'Jan', 'Alter' => '39', 'Jahrgang' => '1981', 'ID' => '3');
$data['kjell'] = array('Name' => 'Kjell', 'Alter' => '4', 'Jahrgang' => '2018', 'ID' => '0');
$data['bjarne'] = array('Name' => 'Bjarne', 'Alter' => '6', 'Jahrgang' => '2015', 'ID' => '2');
$data['monika'] = array('Name' => 'Monika', 'Alter' => '72', 'Jahrgang' => '1950', 'ID' => '1');
This would allow you to access or set any values using that key.
//access
$info = $data['jan']; //array('Name' => 'Jan', 'Alter' => '39', 'Jahrgang' => '1981', 'ID' => '3')
//set
$data['jan']['Name'] = 'Not Jan';
//loop
foreach($data as $slug => $info) {
//$info = array('Name' => 'Jan', 'Alter' => '39', 'Jahrgang' => '1981', 'ID' => '3')
}
Another plus side to this method in your case is it makes sure each "Slug" is unique, because arrays cannot contain duplicate keys.
You could use "function" instead of "nested foreach" like this:
function replace($data,$index){
// count array length
$num = count($data);
if($index < $num){
if($data[$index]['Slug'] === 'jan'){
$a = [ $index => [ "Jahrgang" => "1982" ] ] ;
// replace new array with new values
$re = array_replace($data,$a);
return $re;
}else{
$index ++;
check($data,$index);
}
}
}
replace($data,0);
I have a array with repeated values like this:
[
[
'id' => 112,
'name' => 'John',
'country' => 'Spain',
'age' => 24,
'company' => 'One',
'price' => 10
],
[
'id' => 112,
'name' => 'John',
'country' => 'Spain',
'age' => 24,
'company' => 'Two',
'price' => 15
],
[
'id' => 112,
'name' => 'John',
'country' => 'Spain',
'age' => 24,
'company' => 'Three',
'price' => 20
],
[
'id' => 224,
'name' => 'Paul',
'country' => 'France',
'age' => 25,
'company' => 'One',
'price' => 25
],
[
'id' => 224,
'name' => 'Paul',
'country' => 'France',
'age' => 25,
'company' => 'Two',
'price' => 40
]
]
I need to group same id with name, country and age, and make a "sub array" companies with company and price
array (
112 =>
array (
'id' => 112,
'name' => 'John',
'country' => 'Spain',
'age' => 24,
'companies' =>
array (
0 =>
array (
'company' => 'One',
'price' => 10,
),
1 =>
array (
'company' => 'Two',
'price' => 15,
),
2 =>
array (
'company' => 'Three',
'price' => 20,
),
),
),
224 =>
array (
'id' => 224,
'name' => 'Paul',
'country' => 'France',
'age' => 25,
'companies' =>
array (
0 =>
array (
'company' => 'One',
'price' => 25,
),
1 =>
array (
'company' => 'Two',
'price' => 40,
),
),
),
)
I have tried this code without good results:
$new_array = array();
foreach ($my_array as $item) {
$new_array[$item['id']][] = $item;
$new_array[$item['id']]['companies'][] = $item;
}
Then I tried this:
$new_array = array();
foreach ($my_array as $item) {
$new_array[$item['id']]['temp'] = $item;
$new_array[$item['id']]['companies'][] = $item;
}
Works fine, but I get temp key that I don't want it. For example, with this code I need to access to id items with $new_array [$key]['temp']['id']
I can remove the temp key with another loop:
$final_array = array();
foreach ($new_array $key=>$item) {
$final_array [$key] = $item['temp'];
$final_array [$key]['temp'] = $item['companies'];
}
With this code I can access correctly to id with: $final_array[$key]['id']
Another option is this code:
foreach($array as $v) {
$result[$v['id']]['id'] = $v['id'];
$result[$v['id']]['name'] = $v['name'];
$result[$v['id']]['country'] = $v['country'];
$result[$v['id']]['age'] = $v['age'];
$result[$v['id']]['companies'][] = array('company' => $v['company'],
'price' => $v['price']);
}
But it is not very elegant if we had more keys (phone, email...)
Any ideas?
Nothing wrong with the code you've provided at the end, but here's some ideas for how to make it more tolerant to more array values (as you mentioned, phone, email, etc).
This uses the handy PHP array_diff_key function to remove the array elements you don't want from the "core" records. Then, applying array_diff_key to get those same array elements INTO the "company" records.
// set up the array of keys you don't want in the "original" record
$exclude = ['company' => FALSE, 'price' => FALSE];
// Your original loop
foreach($array as $v) {
// not strictly necessary, but helps readability
$id = $v['id'];
// Assign the "core" record all the values you want, excluding those defined above
// in this case, will remove "company" and "price"
$record = array_diff_key( $v, $exclude );
// only set this if not already set, otherwise wipes out previous companies
if ( ! isset($result[$id] ) ) {
$result[$id] = $record;
$result[$id]['companies'] = [];
}
// strip off the OTHER values from the array you don't want stored with the company
// this will automatically pick up the field NOT excluded above
// in this case, will remove all BUT "company" and "price"
$company = array_diff_key( $v, $record );
$result[$id]['companies'][] = $company;
}
One way to rome...
$collector=array();
foreach($array as $set){
//get a copy
$ref = $set;
//unset company data
unset($ref['company'],$ref['price']);
//make a refer
$r=$ref['id'];
//setup main data if not set before
if(!isset($collector[$r])){
$collector[$r]=$ref;
}
//collect company data
$collector[$r]['companies'][] = array('company'=>$set['company'],'price'=>$set['price']);
}
print_r($collector);
Similar to other answers:
$info = array (
array('id' => 112, 'name' => 'John', 'country' => 'Spain', 'age' => 24, 'company' => 'One', 'price' => 10),
array('id' => 112, 'name' => 'John', 'country' => 'Spain', 'age' => 24, 'company' => 'Two', 'price' => 15),
array('id' => 112, 'name' => 'John', 'country' => 'Spain', 'age' => 24, 'company' => 'Three', 'price' => 20),
array('id' => 224, 'name' => 'Paul', 'country' => 'France', 'age' => 25, 'company' => 'One', 'price' => 25),
array('id' => 224, 'name' => 'Paul', 'country' => 'France', 'age' => 25, 'company' => 'Two', 'price' => 40)
);
$grouped = array();
foreach ($info as $item) {
if (!isset($grouped[$item['id']])) {
$grouped[$item['id']] = $item;
}
$grouped[$item['id']]['companies'][] = array($item['company'],$item['price']);
unset($grouped[$item['id']]['company']);
unset($grouped[$item['id']]['price']);
}
print_r($grouped);
The sample data does not seem to require grouping by more than the id column.
The snippet below will extract/consume the last two elements in each row before pushing the first encountered row with a unique id, then it unconditionally pushes those two extracted rows into the group's companies subset.
Code: (Demo)
$result = [];
foreach ($array as $row) {
$companies = array_splice($row, -2);
$result[$row['id']] ??= $row;
$result[$row['id']]['companies'][] = $companies;
}
var_export($result);
I would like to detect same records and then change quantity of the one record and delete the others. For example, given the following array:
'Cart' => [
(int) 0 => [
'size' => '38',
'code' => '5',
'qn' => (int) 1
],
(int) 1 => [
'size' => '37',
'code' => '5',
'qn' => (int) 1
],
(int) 2 => [
'size' => '37',
'code' => '5',
'qn' => (int) 1
]
],
i would like to print:
'Cart' => [
(int) 0 => [
'size' => '38',
'code' => '5',
'qn' => (int) 1
],
(int) 1 => [
'size' => '37',
'code' => '5',
'qn' => (int) 2
]
],
It looks to me that you're trying to sum quantities (qn) on duplicate sizes (size) and codes (code). One way to achieve this is by looping through the array containing the cart items and building out a new array. I suggest reading about PHP arrays and array_key_exists to learn more as they're used below:
<?php
$arr = [
['size' => '38', 'code' => 5, 'qn' => 1],
['size' => '37', 'code' => 5, 'qn' => 1],
['size' => '37', 'code' => 5, 'qn' => 1],
['size' => '37', 'code' => 4, 'qn' => 1],
];
$newArr = [];
foreach ($arr as $value) {
$key = $value['size'] . ':' . $value['code'];
if (array_key_exists($key, $newArr)) {
$newArr[$key]['qn'] += $value['qn'];
continue;
}
$newArr[$key] = $value;
}
// Resets keys
$newArr = array_values($newArr);
print_r($newArr);
I dont know it is enough for your problem, but try function array_unique
Iterate your array and use array_diff on each subarray.
If the returned array doesn't contain neither size nor code, add the two qn
The function array_unique() works for single dimension array. To find unique elements from multi-dimension array, we need to do a little modification.
Try this:
$array = array_map("serialize", $array);
$output = array_map("unserialize", array_unique($array));
If you want to follow another approach, use this as a reference: Create multidimensional array unique
Please go through following code.
$result = [
0=> ['size' => '38',
'code' => '5',
'qn' => 1
],
1=> ['size' => '37',
'code' => '5',
'qn' => 1
],
2=> ['size' => '37',
'code' => '5',
'qn' => 1
]
];
$finalArr = [];
foreach($result as $k => $v) {
$flag = 0;
foreach($finalArr as $kc => $vc){
if($v['size']==$vc['size'] && $v['code']==$vc['code']){
$flag = 1;
$finalArr[$kc]['qn'] = $finalArr[$kc]['qn'] + 1;
break;
}
}
if($flag==0){
$finalArr[] =
[
'size' => $v['size'],
'code' => $v['code'],
'qn' => 1
];
}
}
echo "<pre>";
print_r($finalArr);
The code is tested against your question and i have explained the code. This gives you solution for any number of arrays and with similar array elements with quantity(qn) incremented as you wanted:
<?php
//Compare the 1st and 2nd array
//Compare the 2st and 3rd array
// and so on
function compare($arr1 = array(), $arr2 = array()) {
$result = array_diff($arr1, $arr2);
return $result;
}
$cart = array(
0 => array('size' => 38, 'code' => 5, 'qn' => 1),
1 => array('size' => 37, 'code' => 5, 'qn' => 1),
2 => array('size' => 37, 'code' => 5, 'qn' => 1),
);
$j = 1;
$cart_total_count = count($cart);//Gives the count of your cart
$final_cart = array();//Final array with qn incremented
for($i=0;$i<$cart_total_count; $i++) {
if (!empty($cart[$i+1])) {//If 2nd array is not present then stop the comparision
if (empty(compare($cart[$i], $cart[$i+1]))){
$j++;
$cart[$i]['qn'] = $j;
$final_cart = $cart[$i];
}
}
}var_dump($final_cart);
//Output
//1. If 2 array are same
//array(3) { ["size"]=> int(37) ["code"]=> int(5) ["qn"]=> int(2) }
//2. If no array are same
//array(0) { }?>
I have two arrays with data in them and I need to compare the two and return the array that are not matched.
I have two arrays that both look like this:
$arr1 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '24', 'country' => 'spain' ),
);
$arr2 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '54', 'country' => 'spffain' ),
);
i would like comparing the array by name,age and country and return me the array that are not matched.
my code so far:
$intersect = array_uintersect($arr1, $arr2, 'compareDeepValue');
echo "<pre>", print_r($intersect);
function compareDeepValue($val1, $val2)
{
return strcmp($val1['age'], $val2['age']);
return strcmp($val1['country'], $val2['country']);
return strcmp($val1['name'], $val2['name']);
}
The code above return the array that are matched. How can i changed the code in order to get the array that are not matched?
EXPECTED OUTPUT:
Array
(
[0] => Array
(
[name] => James
[age] => 21
[country] => spain
)
)
The code mentioned by someone in answers will work, but it's manual labor :)
You could use existing functions to do the job for you. For computing the difference between arrays, you should use array_udiff function (or functions related).
You should write function to compare arrays, and use it to compute the difference, like this:
<?php
$arr1 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '24', 'country' => 'spain' ),
);
$arr2 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '54', 'country' => 'spffain' ),
);
// this function checks if 2 arrays with keys and scalar values are the same
function array_same_check($deepArr1, $deepArr2) {
//check if arrays are the same
$diffArr = array_diff_assoc($deepArr1, $deepArr2);
//if $diffArr has 0 elements - arrays are the same
if (count($diffArr) === 0) {
return 0;
}
// arrays are not the same - return arbitratry 1 or -1
return 1;
}
// now let's compare $arr1 and $arr2 you have
// (meaning: compare the difference between arrays containing arrays) - we use function above
$differing = array_udiff ($arr1, $arr2, 'array_same_check');
print_r($differing);
I copied this code to PHPFiddle and it seems to work as expected.
Your Arrays:
$arr1 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '24', 'country' => 'spain' ),
);
$arr2 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '54', 'country' => 'spffain' ),
);
foreach($arr1 as $key=>$arr)
{
$bool = true;
$ar1 = $arr;
$ar2 = $arr2[$key];
foreach($ar1 as $ky=>$val)
{
if($val != $ar2[$ky])
{
$bool = false;
break;
}
}
if(!$bool)
{
echo "Unmatched Arrays: \r\n";
print_r($ar1); echo " in Main Array 1 & \r\n";
print_r($ar2); echo " in Main Array 2. \r\n";
}
}
try this one
$arr1 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '24', 'country' => 'spain' ),
);
$arr2 = array(
array('name' => 'Alan', 'age' => '34', 'country' => 'usa'),
array('name' => 'James', 'age' => '54', 'country' => 'spffain' ),
);
$tmpArray = array();
foreach($arr1 as $data1) {
$duplicate = false;
foreach($arr2 as $data2) {
if($data1['name'] === $data2['name'] && $data1['age'] === $data2['age'] && $data1['country'] === $data2['country']) $duplicate = true;
}
if($duplicate === false) $tmpArray[] = $data1;
}
echo "<pre>", print_r($tmpArray);
$intersect = array_uintersect($arr1, $arr2, 'compareDeepValue');
print_r($intersect);
// add this and it will return the missing array.
print_r(array_diff_key($arr1, $intersect));
function compareDeepValue($val1, $val2)
{
return strcmp($val1['age'], $val2['age']);
return strcmp($val1['country'], $val2['country']);
return strcmp($val1['name'], $val2['name']);
}
I would like to give you another possible solution. I've checked the code and it seems to fit your needs.
/** #var array $arr1 */
$arr1 = array(
array(
'name' => 'Alan',
'age' => '34',
'country' => 'usa'
),
array(
'name' => 'James',
'age' => '24',
'country' => 'spain'
),
);
/** #var array $arr2 */
$arr2 = array(
array(
'name' => 'Alan',
'age' => '34',
'country' => 'usa'
),
array(
'name' => 'James',
'age' => '54',
'country' => 'spffain'
),
);
/** #var array $notMatched */
$notMatched = array();
/**
* #var int $index
* #var array $element
*/
foreach($arr1 as $index => $element) {
/**
* #var string $key
* #var string $value
*/
foreach($element as $key => $value) {
if($arr2[$index][$key] !== $value) {
$notMatched["arr1"] = $arr1[$index];
$notMatched["arr2"] = $arr2[$index];
}
}
}
if(!empty($notMatched)) {
echo "Unmatched arrays: \r\n";
echo "Array 1:\r\n";
print_r($notMatched["arr1"]);
echo "Array 2:\r\n";
print_r($notMatched["arr2"]);
}
I have an array which is created as a combination of two database queries from two separate databases, it looks similar to:
$arr1 = [
['part' => '1', 'address' => 'aaa', 'type' => '1', 'count' => 5],
['part' => '1', 'address' => 'bbb', 'type' => '1', 'count' => 5],
['part' => '1', 'address' => 'ccc', 'type' => '1', 'count' => 5],
['part' => '2', 'address' => 'aaa', 'type' => '1', 'count' => 5],
['part' => '2', 'address' => 'bbb', 'type' => '1', 'count' => 5],
['part' => '2', 'address' => 'ccc', 'type' => '2', 'count' => 5]
];
I am looking for a way to group this array by part and type values. I also need to know the total of the count values as they are grouped.
The results would be something like:
$arr2 = [
['part' => '1', 'type' => '1', 'count' => 15],
['part' => '2', 'type' => '1', 'count' => 10],
['part' => '2', 'type' => '2', 'count' => 5]
];
but I just can't see how to do this. I have seen a few examples of grouping by a single key/value, but not by multiple values at once.
This function should do the job.
function groupByPartAndType($input) {
$output = Array();
foreach($input as $value) {
$output_element = &$output[$value['part'] . "_" . $value['type']];
$output_element['part'] = $value['part'];
$output_element['type'] = $value['type'];
!isset($output_element['count']) && $output_element['count'] = 0;
$output_element['count'] += $value['count'];
}
return array_values($output);
}
If both databases are on the same database server you would be able to do this using SQLs GROUP BY feature.
The following:
$arr2 = array();
foreach ($arr1 as $a) {
unset($a['address']);
$key = $a['type'] . '-' . $a['part'];
if (isset($arr2[$key])) {
$arr2[$key]['count'] += $a['count'];
} else {
$arr2[$key] = $a;
}
}
$arr2 = array_values($arr2);
Would output
array
0 =>
array
'part' => string '1' (length=1)
'type' => string '1' (length=1)
'count' => int 15
1 =>
array
'part' => string '2' (length=1)
'type' => string '1' (length=1)
'count' => int 10
2 =>
array
'part' => string '2' (length=1)
'type' => string '2' (length=1)
'count' => int 5
Something like
$newarr=array();
foreach ( $arr as $Key => $Value ) {
$newarr[$Value[part]][]=$arr[$key];
}
foreach ( $newarr[part] as $Key => $Value ) {
...
}
Full answer for multi-keys arrays grouping is
// * $arr - associative multi keys data array
// * $group_by_fields - array of fields to group by
// * $sum_by_fields - array of fields to calculate sum in group
function array_group_by($arr, $group_by_fields = false, $sum_by_fields = false) {
if ( empty($group_by_fields) ) return; // * nothing to group
$fld_count = 'grp:count'; // * field for count of grouped records in each record group
// * format sum by
if (!empty($sum_by_fields) && !is_array($sum_by_fields)) {
$sum_by_fields = array($sum_by_fields);
}
// * protected from collecting
$fields_collected = array();
// * do
$out = array();
foreach($arr as $value) {
$newval = array();
$key = '';
foreach ($group_by_fields as $field) {
$key .= $value[$field].'_';
$newval[$field] = $value[$field];
unset($value[$field]);
}
// * format key
$key = substr($key,0,-1);
// * count
if (isset($out[$key])) { // * record already exists
$out[$key][$fld_count]++;
} else {
$out[$key] = $newval;
$out[$key][$fld_count]=1;
}
$newval = $out[$key];
// * sum by
if (!empty($sum_by_fields)) {
foreach ($sum_by_fields as $sum_field) {
if (!isset($newval[$sum_field])) $newval[$sum_field] = 0;
$newval[$sum_field] += $value[$sum_field];
unset($value[$sum_field]);
}
}
// * collect differencies
if (!empty($value))
foreach ($value as $field=>$v) if (!is_null($v)) {
if (!is_array($v)) {
$newval[$field][$v] = $v;
} else $newval[$field][join('_', $v)] = $v; // * array values
}
$out[$key] = $newval;
}
return array_values($out);
}
If this task was necessary in one of my projects, I would craft a snippet that would not need reference variables or any iterated function calls.
Inside the loop, declare the composite temporary key as a variable (since it is used more than once). Push the new row into the result array using the composite key as the temporary first-level key.
Use the null coalescing operator to use the pre-existing count for a given group or zero if the group has not yet been encountered. Then add the new count value to the previously accumulated count.
This technique will unconditionally overwrite the encountered group every time it is repeated. In doing so, the data will be updated with the correct part, type, and count values throughout the iterative process.
When the loop finishes, re-index the result array by calling array_values().
Code: (Demo)
$arr1 = [
['part' => '1', 'address' => 'aaa', 'type' => '1', 'count' => 5],
['part' => '1', 'address' => 'bbb', 'type' => '1', 'count' => 5],
['part' => '1', 'address' => 'ccc', 'type' => '1', 'count' => 5],
['part' => '2', 'address' => 'aaa', 'type' => '1', 'count' => 5],
['part' => '2', 'address' => 'bbb', 'type' => '1', 'count' => 5],
['part' => '2', 'address' => 'ccc', 'type' => '2', 'count' => 5]
];
$result = [];
foreach ($arr1 as $row) {
$compositeKey = $row['part'] . '-' . $row['type'];
$result[$compositeKey] = [
'part' => $row['part'],
'type' => $row['type'],
'count' => ($result[$compositeKey]['count'] ?? 0) + $row['count']
];
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'part' => '1',
'type' => '1',
'count' => 15,
),
1 =>
array (
'part' => '2',
'type' => '1',
'count' => 10,
),
2 =>
array (
'part' => '2',
'type' => '2',
'count' => 5,
),
)
p.s. Ideally, this task probably could/should be performed in the sql but we don't have the details to provide any specific guidance.