PHP суммирует записи массива, где два ключа имеют одинаковое значение

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

Array (
[0] => Array
(
[source] => ABC
[target] => DEF
[total_volume] => 10
)

[1] => Array
(
[source] => ABC
[target] => GHI
[total_volume] => 5
)
[2] => Array
(
[source] => ABC
[target] => DEF
[total_volume] => 5
)
)

Полученный массив должен выглядеть так:

ResultArray (
[0] => Array
(
[source] => ABC
[target] => DEF
[total_volume] => 15
)

[1] => Array
(
[source] => ABC
[target] => GHI
[total_volume] => 5
)
)

Моей первой мыслью было бы пролистать существующий массив и проверить через вложенный цикл через ResultArray, существует ли уже запись с совпадающей парой источник-цель.

Есть ли другой способ, используя array_walk () или аналогичный метод?

Заранее спасибо за помощь!

1

Решение

не красиво, но вот как бы я это сделал с вложенным foreach;

$aStartingArray = array();
$aStartingArray[] = array('source'=>'ABC', 'target' => 'DEF', 'total_volume' => 10);
$aStartingArray[] = array('source'=>'ABC', 'target' => 'GHI', 'total_volume' => 5);
$aStartingArray[] = array('source'=>'ABC', 'target' => 'DEF', 'total_volume' => 5);$aSortedArray = array();

foreach ($aStartingArray as $aArray) {

$bSet = false;

foreach ($aSortedArray as $iPos => $aTempSortedArray) {

if(
$aTempSortedArray['source'] == $aArray['source'] &&
$aTempSortedArray['target'] == $aArray['target']){

$aSortedArray[$iPos]['total_volume'] += $aArray['total_volume'];

$bSet = true;
}

}

if(!$bSet) {

$aSortedArray[] = array(
'source' => $aArray['source'],
'target' => $aArray['target'],
'total_volume' => $aArray['total_volume']
);
}
}var_dump($aSortedArray);
2

Другие решения

Это быстрая попытка (извините, она использует дважды array_walk)

<?php

$a = [
['source' => 'ABC', 'target' => 'DEF', 'total_volume' => 10 ],
['source' => 'ABC', 'target' => 'GHI', 'total_volume' => 5 ],
['source' => 'ABC', 'target' => 'DEF', 'total_volume' => 5 ],
];

$tmp = [];

array_walk($a, function (&$item, $key) use (&$tmp) {
$resKey = $item['source'].'_'.$item['target'];
if (!isset($result[$resKey])) {
$result[$resKey] = 0;
}
$tmp[$resKey] += $item['total_volume'];
});

$result = [];
array_walk($tmp, function (&$item, $key) use (&$result) {
list ($source, $target) = explode('_', $key);
$result[] = ['source' => $source, 'target' => $target, 'total_volume' => $item];
});

var_dump($result);
1

Как насчет этого? Я думаю, немного короче.

$a = [
['source' => 'ABC', 'target' => 'DEF', 'total_volume' => 10 ],
['source' => 'ABC', 'target' => 'GHI', 'total_volume' => 5 ],
['source' => 'ABC', 'target' => 'DEF', 'total_volume' => 5 ],
];
$result = $result2 = [];
array_walk($a, function(&$item, $key) use(&$result) {
if(! isset($result[$item['source']]))
$result[$item['source']] = [];
if(! isset($result[$item['source']][$item['target']]))
$result[$item['source']][$item['target']] = 0;
$result[$item['source']][$item['target']] += $item['total_volume'];
});
foreach($result as $key => $val) {
foreach($val as $k => $v) {
$result2[] = [$key,$k,$v];
}
}
print_r($result2);
1

Еще одна альтернатива. Не лучше, но будет работать.

$arr = [
['source' => 'ABC', 'target' => 'DEF', 'total_volume' => 10 ],
['source' => 'ABC', 'target' => 'GHI', 'total_volume' => 5 ],
['source' => 'ABC', 'target' => 'DEF', 'total_volume' => 5 ],
];

$res = $resulrArr = [];
foreach($arr as $record){
$record = array_values($record);
$res[$record[0].'_'.$record[1]] = !empty($res[$record[0].'_'.$record[1]]) ? $res[$record[0].'_'.$record[1]] + $record[2] : $record[2];
}

$resulrArr = array_map(function($v,$k){
$data = explode('_',$k);
$resulrArr['source'] = $data[0];
$resulrArr['target'] = $data[1];
$resulrArr['total_volume'] = $v;
return $resulrArr;
},$res,array_keys($res));

echo '<pre>'; print_r($resulrArr);
0