У меня есть следующий массив, в котором я хочу суммировать 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 () или аналогичный метод?
Заранее спасибо за помощь!
не красиво, но вот как бы я это сделал с вложенным 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);
Это быстрая попытка (извините, она использует дважды 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);
Как насчет этого? Я думаю, немного короче.
$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);
Еще одна альтернатива. Не лучше, но будет работать.
$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);