Группировка и сумма элементов из массива в пределах foreach

Я просматриваю результирующие множества из двух хранимых процедур, получая результаты в рамках одной хранимой процедуры на основе полей внутри другой.

Два массива, содержащие наборы результатов, представляют собой $customers и $subcustomers .

 foreach($customers as $customer) { foreach($subcustomers as $subcustomer) { if($subcustomer['parent'] == $customer['id']) { if($customer['innumber'] == null && $subcustomer['innumber'] != null) { $chartInboundSub['name'] = $customer['name']; $chartInboundSub['label'] = $subcustomer['innumber']; $chartInboundSub['countInbound'] = $customer['count']; $chartInboundSub['minsInbound'] = ceil($customer['duration'] / 60); $chartInboundSub['customerid'] = $customer['id']; array_push($out['chartInbound'], $chartInboundSub); } } } } 

Текущий вывод print_r($out['chartInbound']) :

 Array ( [0] => Array ( [countInbound] => 426 [minsInbound] => 340 [name] => Telekomm [label] => 01-02 [customerid] => 6 ) [1] => Array ( [countInbound] => 1 [minsInbound] => 2 [name] => Telekomm [label] => 01-02 [customerid] => 6 ) [2] => Array ( [countInbound] => 3 [minsInbound] => 21 [name] => Telekomm [label] => 080 [customerid] => 6 ) [3] => Array ( [countInbound] => 1920 [minsInbound] => 15766 [name] => Telekomm [label] => 084 [customerid] => 6 ) [4] => Array ( [countInbound] => 2332 [minsInbound] => 17521 [name] => Telekomm [label] => 084 [customerid] => 6 ) ... ) 

Вышеуказанные результаты необходимо сгруппировать по name , label , customerid с countInbound и minsInbound , так что:

Желаемый результат должен быть:

 Array ( [0] => Array ( [countInbound] => 427 [minsInbound] => 342 [name] => Telekomm [label] => 01-02 [customerid] => 6 ) [1] => Array ( [countInbound] => 3 [minsInbound] => 21 [name] => Telekomm [label] => 080 [customerid] => 6 ) [2] => Array ( [countInbound] => 4252 [minsInbound] => 33287 [name] => Telekomm [label] => 084 [customerid] => 6 ) ... ) 

Я думаю, что это должно сработать. Я не тестировал код, поэтому я не обещаю.

 $map = array(); $i = 0; foreach($customers as $customer) { foreach($subcustomers as $subcustomer) { if($subcustomer['parent'] == $customer['id']) { if($customer['innumber'] == null && $subcustomer['innumber'] != null) { $key = $customer['name'] . '/' . $subcustomer['innumber'] . '/' . $customer['id']; if(isset($map[$key])) { $out['chartInbound'][$map[$key]]['countInbound'] += $customer['count']; $out['chartInbound'][$map[$key]]['minsInbound'] += ceil($customer['duration'] / 60); } else { $out['chartInbound'][$i] = array( 'name' => $customer['name'], 'label' => $subcustomer['innumber'], 'countInbound' => $customer['count'], 'minsInbound' => ceil($customer['duration'] / 60), 'customerid' => $customer['id'], ); $map[$key] = $i++; } } } } } 

Для каждой комбинации name , label и customerid он создает строковый ключ, который должен быть уникальным для этой комбинации. Затем он проверяет, есть ли какие-либо данные для этого ключа (путем сохранения отдельного списка ключей и их индексов в $out['chartInbound'] ). Если это так, он просто добавляет countInbound и minsInbound . Если это не помещает весь $chartInboundSub в $out['chartInbound'] .

Обратите внимание, что это зависит от уникальности ключа. Если вы, например, допустите / в именах, которые могут быть не такими.

Вместо использования циклов foreach я использую «итератор», который имеет каждый массив PHP.

Предполагая, что массив отсортирован, будет достаточно одного прохода, записывающего «текущий идентификатор группы».

Я использую технику «читать дальше», поэтому тест an'if не нужен, чтобы узнать, что делать с «текущей записью».

рабочий код как 'eval.in'

Код:

 /** * Output stored in here... */ $output = array(); // groupId consists of: name, label, customerid // read ahead - we need the current entry of the source array... $currentEntry = current($source); while ($currentEntry !== false) { // process the array / file / resultset etc. // start of a group... process the first record that every group has... $currentGroupId = getGroupId($currentEntry); $currentGroupCountInbound = $currentEntry['countInbound']; $currentGroupMinsInbound = $currentEntry['minsInbound']; // read the next record as we always 'read ahead' after processing a record... next($source); $currentEntry = current($source); while ($currentGroupId == getGroupId($currentEntry)) { // same group = total the values... $currentGroupCountInbound += $currentEntry['countInbound']; $currentGroupMinsInbound += $currentEntry['minsInbound']; // next entry in the input array - will end this group if not the same... next($source); $currentEntry = current($source); } // end of the current group -- output the information... // add it to an array... or whatever... $output[] = array('groupid' => $currentGroupId, 'countInbound' => $currentGroupCountInbound, 'minsInbound' => $currentGroupMinsInbound); } // show the output... echo '<pre>'; print_r($output); echo '</pre>'; exit; // --------------------------------- function getGroupId($entry = array()) { if (empty($entry)) { return array(); } return array( $entry['name'], $entry['label'], $entry['customerid'] ); } 

Выход:

 Array( [0] => Array( [groupid] => Array( [0] => Telekomm [1] => 01-02 [2] => 6 ) [countInbound] => 427 [minsInbound] => 342 ) [1] => Array( [groupid] => Array( [0] => Telekomm [1] => 080 [2] => 6 ) [countInbound] => 3 [minsInbound] => 21 ) [2] => Array( [groupid] => Array( [0] => Telekomm [1] => 084 [2] => 6 ) [countInbound] => 4252 [minsInbound] => 33287 ) )